views:

124

answers:

3

Hi,

I'm creating a little social network in Rails, where people can add eachother as a friend. I have created a model called 'user', which contains, e-mail, strong md5 hash with salt of password etc...

My question is: how do I create something like an option to add another user as a friend. Is it possible to have something like has_many_and_belongs_to :user in the user model? So a user has many users and belongs to many users. Or should I use an other way, like adding a friendship model which has user1s_id:integer and user2s_id:integer? Which way does twitter do it?

Thanks.

+2  A: 

I would suggest that a user has many relationships, this would leave you free to add new types of relationships in the future.

So you start with a "one user to another user" relationship table (minimally, just two IDs) and then in the future you could add a "one user to a group" relationship table (once you've created groups of course!)

Bigwave
So you actually mean the 'adding a friendship model which has user1s_id:integer and user2s_id:integer' way?
Time Machine
Thanks, I always did this in PHP, but I asked this question to check if there is a more Railsy way. So far as I understand, it's the hard way @EmFi suggested but this one is easier.
Time Machine
What Bigwave describes in not necessarily what I said was the hard way. This solution describing a polymorphic relationship that allows for more detail. It's not exactly clear. But it looks like a description for a unidirectional relationship (ie: As in I might be friends with you, but that doesn't mean you are friends with me).
EmFi
+1  A: 

Essentially you want a join model that joins users to users. But you'll have to use more descriptive terms for Rails.

Twitter doesn't use Rails, but here's how their user associations might work in Rails using Twitter's terminology. Note: Twitter doesn't require bidirectional following (ie just because a user follows another, doesn't mean that second user follows the first)

class User < ActiveRecord::Base
  has_many :followings
  has_many :followers, :through => :followings, :class_name => "User"
  has_many :followees, :through => :followings, :class_name => "User"
end


class Following < ActiveRecord::Base 
# fields: follower_id followee_id (person being followed)
  belongs_to :follower, :class_name => "User"
  belongs_to :followee, :class_name => "User"
end

Forced bidirectional friendship (like Facebook enforces that I cannot be friends with you, unless you are a friends with me) will take a little more work. You will either need to manage reciprocal entries with callbacks, or use custom finder SQL. Using custom finder SQL means that ActiveRecord probably won't be able to manage associations for you.

EmFi
Oh yeah, the do use Rails: http://en.wikipedia.org/wiki/Twitter#Technology
Time Machine
Looks like I'm wrong on the Twitter using Rails issue. I assumed the news about their switch to Scala meant they were giving up Rails entirely.
EmFi
+2  A: 

I'd suggest using the friendship model because db-wise you'll need a join table either way, but making that table explicit will allow you to store more details about the relationship (e.g. "friend" or "family", date added, ...)

FRotthowe