[英]has_many through instead of join query
I have relationship between User
models defined through Friendship
model. 我通过
Friendship
模型定义了User
模型之间的关系。 (ROR 4) (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
However, this does not work and my tests are failing because of SQL queries produced. 但是,这不起作用,并且由于生成了SQL查询,我的测试失败了。
> user.friendships
Query: 查询:
SELECT "friendships".* FROM "friendships"
WHERE "friendships"."user_id" = ?
AND (user_id = 1 OR friend_id = 1) [["user_id", 1]]
So part of WHERE before AND "kills" my actual where. 因此,在AND之前, WHERE的一部分会“杀死”我的实际位置。 I made a workaround by making instance method:
我通过制作实例方法来解决:
def friendships
self.class
.select('friendships.* FROM `friendships`')
.where('user_id = :id OR friend_id = :id', id)
end
Is there a way I can remove my instance method and modify has_many relation to produce the SQL I want? 有什么方法可以删除实例方法并修改has_many关系以生成所需的SQL?
> Friendship.request(user, friend)
> friend.requested_friends
Query: 查询:
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]]
It obviously isn't what I need so I made a workaround by removing has_many :requested_friends
and making an instance method: 显然,这不是我所需要的,因此我通过删除
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
Is there any way I can modify my has_many :requested_friends
relation to produce same SQL as my instance method? 有什么方法可以修改
has_many :requested_friends
关系以产生与实例方法相同的SQL?
Very confusing - I'd do something like this: 非常令人困惑-我会做这样的事情:
#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
You'd have a join table which looks like this: 您将有一个如下所示的联接表:
user_friendships
id | user_id | friend_id | other | info | created_at | updated_at
This should work (I'm not sure about the self referential association). 这应该工作(我不确定自我参照关联)。 If it does, it will allow you to call:
如果是这样,它将允许您调用:
@user.friends
I hope this helps? 我希望这有帮助?
you cannot achieve the SQL you want using has_many
method with condition. 您不能通过条件使用
has_many
方法来实现所需的SQL。 The reason is that the block you pass to the method is only additional condition, on top of the standard query which checks if user_id = ?
原因是,传递给该方法的块只是附加条件,它位于检查
user_id = ?
的标准查询之上user_id = ?
. 。
Instead you can simplify your instance method a little bit 相反,您可以稍微简化实例方法
def friendships Friendship.where('user_id = :id or friend_id = :id', id) end
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.