我正在开发一个模拟用户之间友谊的应用程序。
class User
has_many :friendships
has_many :friends,
:through => :friendships,
:conditions => "status = #{Friendship::FULL}"
end
class Friendship
belongs_to :user
belongs_to :friend, :class_name => "User", :foreign_key => "friend_id"
end
当两个用户成为朋友时,会创建友谊类的两个实例,一个用于友谊的每个方向。这是必要的,因为可以在每个方向上设置不同的权限,也为了便于查找,所以我们总是按 user_id 进行搜索,而无需创建第二个索引并且需要加倍搜索。
是否有可能使用 find 或命名范围来拉取朋友以及反友谊?我想这样做是因为我允许用户编辑存储在他们自己的友谊分支中的友谊权限,因此当我向用户显示朋友的信息时,我需要检查对面的分支以查看如何设置权限。(顺便说一句,这似乎是一种合乎逻辑的做事方式吗?要么存储到对面,要么在展示前必须咨询对面,这两种方式都令人不快。)
我已经设法编写了一批完成这项工作的 SQL:
def self.secure_friends(user_id)
User.find_by_sql("SELECT u.*, cf.permissions
FROM users u
INNER JOIN friendships f ON u.id = f.friend_id
INNER JOIN friendships cf ON u.id = cf.user_id AND cf.friend_id = #{user_id}
WHERE ((f.user_id = #{user_id}) AND (f.status = #{Friendship::FULL}))")
end
该函数返回用户的所有朋友姓名和 ID,以及权限。但是,这似乎并不理想,这意味着我必须通过调用friend.permissions 来访问权限,其中权限实际上不是朋友的成员,而是由find_by_sql 合并为一个属性。总而言之,我真的更愿意使用 named_scope 或 find 调用来执行此操作,但不幸的是,我使用该方法所做的每一次尝试都导致了错误,因为 Rails 因加入相同的 Friendship 连接表而窒息查询两次。