2013-10-12 45 views
4

我想在我的應用中實現用戶的朋友系統,所以我發現rails space解決方案非常好,想法是創建兩行the Friendships table:第一行發件人邀請,而第二個用於接收器在rails中實現友誼模型的最佳方式

用戶之間的關係被設定與has_many協會這樣的:

用於接受用戶
has_many :friendships 
has_many :friends, :through => :friendships, :conditions => "status = 'accepted'" 

方法爲朋友是這樣的:

# 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()方法是:

# 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 

這個有優勢,我們可以執行一個請求以從兩側所有的朋友(無論用戶是誰發來的邀請或朋友是誰送它)

,但我認爲這有缺點,例如,如果在現實中有500樓的朋友,友誼表將包含「500X2 = 1000」行

第二個解決方案是與反向關聯喜歡在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 

但在這裏,如果你想獲得的所有朋友的用戶,你應該使用兩個要求:

user.friends 
user.inverse_friends 

這是不是最好的方式在所有如果你有一個巨大的友誼表...

我想知道什麼是從上述兩個最好的方法,然後有一種方法來優化它?如果還有另一個超級方法,我會感激

回答

4

我寧願需要兩個朋友之間的連接的版本,每個方向一個。原因與你提到的一樣:它允許用戶的朋友進行更多類似Rails的查詢。

而且我認爲這將是更清晰的有友誼請求(一個方向)和現有的友誼(兩個方向)

不同的表,因爲你在中間的友誼模式,我建議使用的魔法回調。如果您定義了一些回調函數,則必須有可能您只需要在連接的一端進行檢查,回調函數應該能夠創建(或刪除)匹配的補充。

# 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 

這只是一個最初的想法,肯定一些驗證和回調失蹤......

+0

嗨@spickermann謝謝你的回答,你怎麼看待這將是X2表的大小? – medBo

+0

雙桌大小很長時間不會成爲問題。在生產數據庫中有一張友誼表,它擁有4M以上的條目,甚至在磁盤上也不會佔用200MB。 – spickermann

+0

謝謝,您的意見讓我放心,還有一個關於您的代碼的問題,請問您的意思是after_save:decide_friendship – medBo