Reputation: 1156
I am developing an application with the typical social features: essentially, two users can be friends. This is done through an associative class called "Friendship" that contains the id of the two users. Obviously both keys can't be called "user_id". The normal way would be to give different names to both keys and make it work with :class_name.
The problem is that the relation is completely reciprocal, as the friendship can't be only one-side: it works like Facebook, not like Twitter. I don't want to add information naming the keys "creator" and "acceptor", and using numbers "user_1_id" or "user_2_id" sounds terrible.
The question: is there any convention in Rails for this naming problem?
Upvotes: 0
Views: 474
Reputation: 64363
I typically normalize the data in such situations.
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
This way you are optimizing the friend queries.
Edit
If you must store the friend relationship in one row then add an additional association to the User
model:
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}
}
}
Now you can use the new association as follows:
user1.friends << user2
user3.friends << user1
user1.network_friends # [ user2, user3]
Upvotes: 1
Reputation: 3057
There's a railscasts tutorial on this subject using user
and friend
which seems sensible. It also has support for the reciprocal relation.
Upvotes: 1