Topic: A user has many users ... but how?

I'm trying to implement a User model that would have a relationship with other users. Moreover, a user could be friends with another user.

This would be accomplished by a HABTM relationship, but I'm getting a little confused about how to set this up. The relationship would always go both ways and never one way, and would needs to be able to be searched from either side of the relationship.

Ie:

Bob adds Janet. Janet and Bob are friends. (Relationship created.)
or Janet adds Bob. Bob and Janet are friends.

Bob removes Janet. Janet and Bob are no longer friends. (Relationship erased/removed)
or Janet removes Bob. Bob and Janet are no longer friends.

Bob needs to be able to see that he's friends with Janet.
Janet needs to be able to see that she's friends with Bob.

What sort of join table would be needed? user_user? That works fine in this situation because the relationship goes both ways and it doesn't matter who added who. The problem would be when searching/displaying friends. user.users wouldn't allow me to specify from what side of the relationship I'm coming from. If Bob added Janet then he could see Janet by doing user.users and she would pop up, but if Janet wanted to see that relationship she wouldn't be able to go user.users because she was the second user. No?

Would the linked table use user_a_id & user_b_id specifically as the names of the fields in the database? normally the table would be house_id & brick_id if that was the relationship, but what happens when there are relationships with each other?

Thanks for any thoughts!

Re: A user has many users ... but how?

This is what I would do...  Forget the relationships.  They are very nice in most cases, but not in cases these.  Most of the time you can express a relationship in a single line of code anyway, when not using the built-in relationship methods.  I would use a map table, say user_friends, with from_user_id and to_user_id fields.  I would then add methods that find the records the way I want to work with them. 
There's two possible ways I could see going with the data.  One way would be to keep the actual relationship intact (with or without symmetry.)  For example, if Jim adds Bob, the record would be reversed as opposed to Bob adding Jim.  If Jim adds Bob, it would be up to you do decide if Jim actually shows up as Bob's friend if Bob hasn't added Jim.
The other way I could see storing the data is just to compare the two user_ids, and always store the lesser in the first column.  Then, it is normalized such that user_id 10's friends can be found by searching the first column, etc.
There is not one way to do this, obviously.  There are probably 10 different ways to accomplish this.

BrewControl.com - Brewery and Brewpub management powered by RoR

Re: A user has many users ... but how?

I have done exactly this on my site (like, for example my profile www.fitaculous.com/matt)

Mine is a tad more complicated in that users must approve friend requests (it works identically to myspace), but the core is two models, Users and Friendships

User --> standard User model table

Friendships
-----------
user_id, integer
friend_id, integer

the models are defined as

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.to_s, :foreign_key => 'friend_id'
end


then creating a friendship is...

    new_friend1 = Friendship.new(:user_id => current_user.id, :friend_id => params[:id])
    new_friend2 = Friendship.new(:user_id => params[:id], :friend_id => current_user.id)

    new_friend1.save
    new_friend2.save


In my system, friendships are always symmetrical and to accomplish that I just always create two Friendship entries, one going in each direction. There is probably a better way to do it, but this works well for me. I also destroy both Friendship models if one person ends the friendship.

Then when you have a user model object, the friends parameter is an array of user objects of all of the friends this person has.

Last edited by tortoise (2007-03-21 13:43:23)

Re: A user has many users ... but how?

Rails Recipes talks about this subject in detail and provides a good solution. It's Recipe 18. I don't feel right about copying it here though.

Railscasts - Free Ruby on Rails Screencasts

Re: A user has many users ... but how?

Thanks for all your input. I should have found that Rails Recipe on my own, but I wasn't aware of the exact term "SELF-REFERENTIAL MANY-TO-MANY RELATIONSHIPS".

Cheers!