在 Rails 中实现友谊模型的最佳方式 [英] the best way to implement a friendship model in rails

查看:32
本文介绍了在 Rails 中实现友谊模型的最佳方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在我的应用程序中实现一个用户的朋友系统,所以我发现 rails space 解决方案非常好,这个想法是在 Friendships 表 中创建两行: 第一行是发件人邀请,第二行是收件人

I want to implement a user's friends system in my app so i found the rails space solution very nice, the idea there is to create two lines in the Friendships table : the first line for the sender invitation, and the second one for receiver

用户之间的关系使用 has_many 关联设置,如下所示:

relation between users is setup with has_many association like this:

has_many :friendships
has_many :friends, :through => :friendships, :conditions => "status = 'accepted'"

接受用户为朋友的方法是这样的:

method for accepting a user as friend is like this :

# Accept a friend request.
def self.accept(user, friend)
    transaction do
        accepted_at = Time.now
        accept_one_side(user, friend, accepted_at)
        accept_one_side(friend, user, accepted_at)
    end
end 

accept_one_side() 方法是:

accept_one_side() method is :

# Update the db with one side of an accepted friendship request.
def self.accept_one_side(user, friend, accepted_at)
    request = find_by_user_id_and_friend_id(user, friend)
    request.status = 'accepted'
    request.accepted_at = accepted_at
    request.save!
end

这样做的好处是我们可以执行一个请求来获取双方的所有好友(无论是用户发出邀请还是好友发出邀请)

this have advantage that we can executing one request to get all friends from the two side (either the user is who sent the invitation or the friend is who sent it)

但我认为这有缺点,例如,如果现实中有 500 个朋友,则 Friendships 表将包含500X2 = 1000";线

but i think this have disadvantage if for example in reality there is 500 friends, Friendships table will contains "500X2 = 1000" lines

第二种解决方案是与 has_many through 进行反向关联,如 RailsCast #163 自引用关联 :

the second solution is to make a reverse association with has_many through like explained in RailsCast #163 Self-Referential Association :

has_many :friendships
has_many :friends, :through => :friendships
has_many :inverse_friendships, :class_name => "Friendship", :foreign_key => "friend_id"
has_many :inverse_friends, :through => :inverse_friendships, :source => :user

但是在这里,如果您想为用户获取所有朋友,您应该为此使用两个请求:

but here if you want to get all friends for a user you should use two request for that :

user.friends
user.inverse_friends

如果你有一个巨大的友谊表,这根本不是最好的方法......

which is not the best way at all if you have a huge Friendships table ...

我想知道以上两种方法中最好的一种是什么,那么有没有一种方法可以优化它?如果还有另一种超级方法我会很感激

what i want to know is what is the best one method from the two above, then there is a way to optimize it ? if there is also another super method i will be thankful

推荐答案

我更喜欢朋友之间需要两个连接的版本,每个方向一个.原因与您提到的相同:它允许对用户的朋友进行更多类似 Rails 的查询.

I would prefer the version that needs two connections between the friends, one for each direction. The reason is the same you mentioned: It allows more Rails-like queries on a user's friends.

此外,我认为对于友谊请求(一个方向)和现有友谊(两个方向)有不同的表会更清楚

Furthermore I think it would be clearer to have different tables for friendship request (one direction) and existing friendships (two directions)

既然中间有友情模型,我建议使用回调的魔力.如果你定义了一些回调,那肯定有可能你只需要为连接的一侧吃蛋糕,回调应该能够创建(或删除)匹配的补码.

Since you have a friendship model in the middle, I suggest to use the magic of callbacks. If you define some callbacks, it must be possible that you only have to take cake for one side of the connection, the callback should should be able to create (or delete) the matching complement.

# in friendship_requests
after_save :created_friendship

def accept
  update_attributes(:status  => 'accepted')
end

private
  def created_friendship
    sender.friends << receiver  if status_changed? && status == 'accepted'
  end


# in user.rb
has_and_belongs_to_many :friends, after_add:    :create_complement_friendship,
                                  after_remove: :remove_complement_friendship

private
  def create_complement_friendship(friend)
    friend.friends << self  unless friend.friends.include?(self)
  end

  def remove_complement_friendship(friend)
    friend.friends.delete(self)
  end

这只是第一个想法,肯定缺少一些验证器和回调......

This is just a first idea, for sure some validators and callbacks are missing...

这篇关于在 Rails 中实现友谊模型的最佳方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆