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

时间:2021-05-16 14:32:04

I'm currently working on a small social networking application and right now I'm trying to create a model that represents friendships between users. This is what I came up with so far:

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

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

My friendship model has a field confirmed as boolean which I'd like to use to define a friendship as pending or confirmed.

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

How can I access all pending request for a certain user? Can I somehow define this using Rails' scope method? Something like

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

current_user.friendships.requests # => [Friendship, Friendship, ...]

would be great.

会很好。

How can I make this association bidirectional? Do I simply add another friendship once one has confirmed a friend request such that my friendship table would look similar to this:

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

| user_id | friend_id | confirmed |
-----------------------------------
| 1       | 2         | true      |
| 2       | 1         | true      |

5 个解决方案

#1


30  

To access all pending friendships you can use an association:

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

has_many :pending_friends,
         :through => :friendships,
         :source => :friend,
         :conditions => "confirmed = 0"  # assuming 0 means 'pending'

To make the friendship bidirectional, you may want to replace your boolean confirmed column with a string status column that has one of the following three values: 'pending', 'requested' and 'accepted' (optionally 'rejected'). This will help keep track of who made the friendship request.

为了使友谊成为双向的,您可能希望将字符串状态列替换为具有以下三个值之一的字符串状态列:'pending','requested'和'accepted'(可选地'rejected')。这将有助于跟踪谁发出了友谊请求。

When a friendship request is sent (say from Foo to Bar), you create two friendship records (encapsulated in a transaction): one requested and one pending to reflect resp. that Bar has a requested friendship from Foo and Foo has a pending friendship with Bar.

当发送友谊请求时(例如从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

When the friendship is accepted (e.g. by Bar), both friendship records are set to accepted.

当友谊被接受时(例如通过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

This is largely covered in chapter 14 of the Railspace book by Michael Hartl and Aurelius Prochazka. Here's the source code which should help you refine your solution.

迈克尔·哈特尔(Michael Hartl)和奥雷利乌斯·普罗哈兹卡(Aurelius Prochazka)在“铁路空间”一书的第14章中对此进以下是可帮助您优化解决方案的源代码。

#2


12  

The ultimate reference:

最终参考:

http://railscasts.com/episodes/163-self-referential-association

http://railscasts.com/episodes/163-self-referential-association

#3


4  

A short answer is yes. Just make another friendship record to represent bidirectional association.

简短的回答是肯定的。只需创建另一个友谊记录即可表示双向关联。

I wrote a gem called has_friendship for this kind of problem. All you need to do is drop in has_friendship in your model, and all the associations and methods will be taken care of.

我写了一个名为has_friendship的宝石来解决这类问题。您需要做的就是在模型中放入has_friendship,并且将处理所有关联和方法。

Hope this helps!

希望这可以帮助!

#4


2  

Read up on this tutorial illustrating a relationship model on Rails Tutorials. It should be exactly what you are looking for.

阅读本教程,了解Rails教程中的关系模型。它应该是你正在寻找的。

#5


1  

I recommend you the book RailsSpace: Building a Social Networking Website. It clearly explains how to implement a friendship model. Though it isnt extensible to other forms of relationship but is pretty applicable for your problem.

我推荐你RailsS​​pace:建立一个社交网站网站。它清楚地解释了如何实现友谊模型。虽然它不能扩展到其他形式的关系,但非常适合您的问题。

#1


30  

To access all pending friendships you can use an association:

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

has_many :pending_friends,
         :through => :friendships,
         :source => :friend,
         :conditions => "confirmed = 0"  # assuming 0 means 'pending'

To make the friendship bidirectional, you may want to replace your boolean confirmed column with a string status column that has one of the following three values: 'pending', 'requested' and 'accepted' (optionally 'rejected'). This will help keep track of who made the friendship request.

为了使友谊成为双向的,您可能希望将字符串状态列替换为具有以下三个值之一的字符串状态列:'pending','requested'和'accepted'(可选地'rejected')。这将有助于跟踪谁发出了友谊请求。

When a friendship request is sent (say from Foo to Bar), you create two friendship records (encapsulated in a transaction): one requested and one pending to reflect resp. that Bar has a requested friendship from Foo and Foo has a pending friendship with Bar.

当发送友谊请求时(例如从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

When the friendship is accepted (e.g. by Bar), both friendship records are set to accepted.

当友谊被接受时(例如通过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

This is largely covered in chapter 14 of the Railspace book by Michael Hartl and Aurelius Prochazka. Here's the source code which should help you refine your solution.

迈克尔·哈特尔(Michael Hartl)和奥雷利乌斯·普罗哈兹卡(Aurelius Prochazka)在“铁路空间”一书的第14章中对此进以下是可帮助您优化解决方案的源代码。

#2


12  

The ultimate reference:

最终参考:

http://railscasts.com/episodes/163-self-referential-association

http://railscasts.com/episodes/163-self-referential-association

#3


4  

A short answer is yes. Just make another friendship record to represent bidirectional association.

简短的回答是肯定的。只需创建另一个友谊记录即可表示双向关联。

I wrote a gem called has_friendship for this kind of problem. All you need to do is drop in has_friendship in your model, and all the associations and methods will be taken care of.

我写了一个名为has_friendship的宝石来解决这类问题。您需要做的就是在模型中放入has_friendship,并且将处理所有关联和方法。

Hope this helps!

希望这可以帮助!

#4


2  

Read up on this tutorial illustrating a relationship model on Rails Tutorials. It should be exactly what you are looking for.

阅读本教程,了解Rails教程中的关系模型。它应该是你正在寻找的。

#5


1  

I recommend you the book RailsSpace: Building a Social Networking Website. It clearly explains how to implement a friendship model. Though it isnt extensible to other forms of relationship but is pretty applicable for your problem.

我推荐你RailsS​​pace:建立一个社交网站网站。它清楚地解释了如何实现友谊模型。虽然它不能扩展到其他形式的关系,但非常适合您的问题。