如何在Rails 3中为社交网络应用程序实现友谊模型?

t6d*_*t6d 20 ruby activerecord ruby-on-rails has-many-through

我目前正在开发一个小型社交网络应用程序,现在我正在尝试创建一个代表用户之间友谊的模型.这是我到目前为止提出的:

class User < ActiveRecord::Base

  # ...
  has_many :friendships
  has_many :friends, :through => :friendships

end

class Friendship < ActiveRecord::Base
  belongs_to :user
  belongs_to :friend, :class_name => 'User'
end
Run Code Online (Sandbox Code Playgroud)

我的友谊模型有一个确认为布尔值的字段,我想用它来定义一个待定或确认的友谊.

如何访问特定用户的所有待处理请求?我可以使用Rails的范围方法以某种方式定义它吗?就像是

current_user.friendships.requests # => [Friendship, Friendship, ...]
Run Code Online (Sandbox Code Playgroud)

会很好.

如何使这种关联双向化?一旦确认了朋友请求,我就会添加另一个友谊,这样我的友谊表看起来就像这样:

| user_id | friend_id | confirmed |
-----------------------------------
| 1       | 2         | true      |
| 2       | 1         | true      |
Run Code Online (Sandbox Code Playgroud)

mbr*_*ing 30

要访问所有待处理的友谊,您可以使用关联:

has_many :pending_friends,
         :through => :friendships,
         :source => :friend,
         :conditions => "confirmed = 0"  # assuming 0 means 'pending'
Run Code Online (Sandbox Code Playgroud)

为了使友谊是双向的,你可能需要更换您的布尔确认柱用绳子状态具有以下三个值中的一列:"待定","请"和"接受"(可选的"拒绝").这将有助于跟踪谁发出了友谊请求.

当发送友谊请求(例如从Foo到Bar)时,您创建两个友谊记录(封装在事务中):一个请求,一个挂起以反映resp.Bar与Foo和Foo有着友好的友谊与Bar有着友好的关系.

  def self.request(user, friend)
    unless user == friend or Friendship.exists?(user, friend)
      transaction do
        create(:user => user, :friend => friend, :status => 'pending')
        create(:user => friend, :friend => user, :status => 'requested')
      end
    end
  end
Run Code Online (Sandbox Code Playgroud)

当友谊被接受时(例如通过Bar),两个友谊记录都被设置为被接受.

  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

  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
Run Code Online (Sandbox Code Playgroud)

迈克尔·哈特尔(Michael Hartl)和奥雷利乌斯·普罗哈兹卡(Aurelius Prochazka)在Railspace的第14章中对此进行了详细介绍.以下是可帮助您优化解决方案的源代码.