2012-07-03 33 views
0

我正在開發一個具有典型社交功能的應用程序:實質上,兩個用戶可以成爲朋友。這是通過一個名爲「Friendship」的關聯類來完成的,該類包含兩個用戶的id。顯然,這兩個鍵不能被稱爲「user_id」。通常的做法是給兩個鍵賦予不同的名稱,並使其與:class_name一起工作。在Rails中相同類的對象之間關聯的命名約定

問題是,關係是完全相互的,因爲友誼不能只是單方面的:它像Facebook一樣工作,不像Twitter。我不想添加命名密鑰「creator」和「acceptor」的信息,並且使用數字「user_1_id」或「user_2_id」聽起來很糟糕。

問題:Rails中是否存在這種命名問題的約定?

+1

計算機科學中只有兩件難事... http://laughingmeme.org/2005/12/23/there-are-only-two-hard-東西在計算機科學緩存失效和命名事情/ – phoet

回答

1

我通常在這種情況下規範化數據。

class User 
    has_many :friendships 
    has_many :friends 
end 

class Friendship 
    belongs_to :user 
    belongs_to :friend, :class_name => "User" 

    after_create :reciprocate_friendship 

    def reciprocate_friendship  
    return if friend.friends.exists?(user) # do nothing if reciprocal friendship exists 
    friend.friends << user 
    end 
end 

這樣您就可以優化好友查詢。

編輯

如果您必須存儲在一排的朋友關係,然後建立附加關聯添加到User型號:

has_many :network_friends, :class_name => "User", :finder_sql => Proc.new { 
    %Q{ 
    SELECT * FROM users 
    JOIN friendships 
     ON (users.id = friendships.user_id OR users.id = friendships.friend_id) 
    WHERE users.id = #{id} 
    } 
} 

現在你可以使用新的關聯如下:

user1.friends << user2 
user3.friends << user1 
user1.network_friends # [ user2, user3] 
+0

但是,像這樣你正在複製數據。用戶1和用戶2之間的友誼會在FriendShip表中生成兩條記錄。 – Gawyn

+0

您正在規範化數據,以便您的朋友查詢速度更快。你將不得不求助於使用大量的自定義sql來獲得標準的rails關聯。與便捷地訪問數據相比,數據重複的支付成本很小。我已經用解決方案更新了我的答案,以便將朋友郵寄一排。 –

+0

在這裏沒有其他人覺得**友誼**應該是一個單詞嗎? – Pierre

1

有一個railscasts tutorial在這個問題上使用userfriend這似乎是明智的。它也支持相互關係。

+0

是的,但我不喜歡這種解決方案。我們談論的是朋友,而不是關於朋友和「inverse_friends」。也許這或多或少會好,如果它包含第三個關係,那就是加入其他兩個關係的結果。 – Gawyn