has_many通过而不是连接查询

时间:2014-03-09 11:17:53

标签: sql ruby-on-rails

我通过User模型定义的Friendship模型之间存在关系。 (ROR 4)

用户

class User < ActiveRecord::Base
  has_many :friendships, ->(object) { where('user_id = :id OR friend_id = :id', id: object.id) }

  has_many :friends, ->(object) { where(friendships: {status: 'accepted'}).where('user_id = :id OR friend_id = :id', id: object.id) }, through: :friendships, source: :friend

  has_many :requested_friends, -> { where(friendships: {status: 'pending'}) }, through: :friendships, source: :friend
end

友谊

class Friendship < ActiveRecord::Base
  belongs_to :user
  belongs_to :friend, class_name: 'User'

  def self.request(user, friend)
    unless user == friend or find_friendship(user, friend) != nil
      create(user: user, friend: friend, status: 'pending')
    end
  end

  def self.find_friendship(user, friend)
    ids = [user.id, friend.id]
    where(user_id: ids, friend_id: ids).first
  end
end

然而,由于产生了SQL查询,这不起作用并且我的测试失败了。

友谊关系

> user.friendships

查询:

SELECT "friendships".* FROM "friendships" 
    WHERE "friendships"."user_id" = ? 
      AND (user_id = 1 OR friend_id = 1)  [["user_id", 1]]

AND 之前 WHERE 的一部分“杀死”我的实际位置。我通过制作实例方法做了一个解决方法:

def friendships
  self.class
    .select('friendships.* FROM `friendships`')
    .where('user_id = :id OR friend_id = :id', id)
end

有没有办法可以删除我的实例方法并修改has_many关系来生成我想要的SQL?

Requested_friends relation

> Friendship.request(user, friend)
> friend.requested_friends

查询:

SELECT "users".* FROM "users" 
    INNER JOIN "friendships" ON "users"."id" = "friendships"."friend_id" 
    WHERE "friendships"."status" = 'pending' 
      AND "friendships"."user_id" = ? 
      AND (user_id = 2 OR friend_id = 2)  [["user_id", 2]]

显然这不是我需要的,所以我通过删除has_many :requested_friends并制作实例方法来解决方法:

def requested_friends
  self.class
    .joins('JOIN `friendships` friendships ON users.id = friendships.user_id')
    .where('friendships.status = ?', 'pending')
    .where('friendships.friend_id = ?', id)
end

有没有什么方法可以修改我的has_many :requested_friends关系来生成与我的实例方法相同的SQL?

2 个答案:

答案 0 :(得分:0)

非常混乱 - 我会做这样的事情:

#app/models/user.rb
Class User < ActiveRecord::Base
    has_many :friendships, class_name: "user_friendships", association_foreign_key: "user_id", foreign_key: "friend_id", 
    has_many :friends, class_name: "User", through: :friendships
end

#app/models/user_friendship.rb
Class UserFriendship < ActiveRecord::Base
    belongs_to :user
    belongs_to :friend, class_name: "User"
end 

你有一个如下所示的联接表:

user_friendships
id | user_id | friend_id | other | info | created_at | updated_at

这应该有用(我不确定自我引用关联)。如果是,它将允许您致电:

@user.friends

我希望这有帮助吗?

您可能也会受益于this gem

答案 1 :(得分:0)

使用带有条件的has_many方法无法实现所需的SQL。原因是传递给方法的块只是附加条件,在标准查询之上检查user_id = ?

相反,您可以稍微简化实例方法

def friendships Friendship.where('user_id = :id or friend_id = :id', id) end