A User to User Relationship

Hi,

I’m trying to do a project where each User has many Friends and each
Friend has many Users. Therfore, each person can have multiple friends
and each friend is associated with multiple users.

The interesting thing is that a Friend is just another User.

I don’t think I need a Friend model, but what I need is to create a join
table that has a :user_id and a :friend_id (which is another :user_id).
I’m not quite sure how to do that without creating a model for Friend.

Am I on the right page or would someone do this differently?

Any thoughts would be greatfully appreciated.

S

I haven’t actually tested this… but it seems to me like you could just
declare within User that User has_and_belongs_to_many :users

This would probably create the join table, which would just be user to
user
pairings. Again, I haven’t actually tested this, but I don’t see why it
wouldn’t work the same as usual.

Hopefully that helped a little,
Tyler P.

On 10/14/06, Shawn Szauksztun-Zvinis [email protected]

You’ll need a many-many relationship with User to itself. You use two
tables for this kind of relationship:

  • users
    and
  • user_user

user_user has no id column, but does have user_one_id and user_two_id
columns. It’s basically a map of friends:

user id=1 is friends with user id=2
user id=1 is friends with user id=3
user id=2 is friends with user id=4

etc.

Just as you wuold use ‘belongs to’ and ‘has many’ in your model, you
use:

has_and_belongs_to_many :users, :join_table => “user_user”

Rails should then give you nice friendly access to your friends. You
don’t even need to define a single reference in the user table! I
haven’t used it myself yet, but I believe you’ll get access to the
friends as an array :-

my_user = User.find(:first)
my_user.users

(I may be wrong!)

Ben

I see where you’re going with this, but rails refuses to recognize
user_one_id and user_two_id. It’s searching for user_id in user_user. I
tried to overwrite this in the model with :foreign_key and
:association_foreign_key, but no luck.

The code I’m using to create the new friend is:

user = User.find(:first)
user.users << User.find_by_display_name(“blahblah”)

This adds “a” user to to the user_user table only if it has the field
user_id and leaves the other field which would hold the second users
user_id as NULL. Now if you try to add that as :user_two_id it thinks
you’re talking about the original User model and returns a :user_two_id
not found in Users.

I think we’re on the right page, but something’s missing.

Any thoughts anyone?

Thanks again.

Ben wrote:

You’ll need a many-many relationship with User to itself. You use two
tables for this kind of relationship:

  • users
    and
  • user_user

user_user has no id column, but does have user_one_id and user_two_id
columns. It’s basically a map of friends:

user id=1 is friends with user id=2
user id=1 is friends with user id=3
user id=2 is friends with user id=4

etc.

Just as you wuold use ‘belongs to’ and ‘has many’ in your model, you
use:

has_and_belongs_to_many :users, :join_table => “user_user”

Rails should then give you nice friendly access to your friends. You
don’t even need to define a single reference in the user table! I
haven’t used it myself yet, but I believe you’ll get access to the
friends as an array :-

my_user = User.find(:first)
my_user.users

(I may be wrong!)

Ben

As usual, shortly after posting, I’ve come up with something. I think
it’s because I’m coding at 3:00am in the morning and missing stuff I
should have caught instantly.

Here’s the solution if anyone cares:

class User < ActiveRecord::Base

has_and_belongs_to_many :users, :join_table => “friends”,
:association_foreign_key => “user_two_id”, :foreign_key => “user_one_id”

end

If you don’t manually set the associations and keys, there’s no way this
would work for a one-to-one many-to-many relationship in the same table.
Rails get’s lost into trying to figure out why it’s seeing twins and why
it can’t distinguish the difference between the two.

I said before that I’m injecting the friends as:

user array << new friend

Doing this adds User 2 as a friend of User 1. If I look up User 2’s
friends I get NIL. How do I make this relationship go both ways? That if
User 1 adds User 2, User 1 gets added to the array of friends in User 2?

Shawn Szauksztun-Zvinis wrote:

I see where you’re going with this, but rails refuses to recognize
user_one_id and user_two_id. It’s searching for user_id in user_user. I
tried to overwrite this in the model with :foreign_key and
:association_foreign_key, but no luck.

The code I’m using to create the new friend is:

user = User.find(:first)
user.users << User.find_by_display_name(“blahblah”)

This adds “a” user to to the user_user table only if it has the field
user_id and leaves the other field which would hold the second users
user_id as NULL. Now if you try to add that as :user_two_id it thinks
you’re talking about the original User model and returns a :user_two_id
not found in Users.

I think we’re on the right page, but something’s missing.

Any thoughts anyone?

Thanks again.

Ben wrote:

You’ll need a many-many relationship with User to itself. You use two
tables for this kind of relationship:

  • users
    and
  • user_user

user_user has no id column, but does have user_one_id and user_two_id
columns. It’s basically a map of friends:

user id=1 is friends with user id=2
user id=1 is friends with user id=3
user id=2 is friends with user id=4

etc.

Just as you wuold use ‘belongs to’ and ‘has many’ in your model, you
use:

has_and_belongs_to_many :users, :join_table => “user_user”

Rails should then give you nice friendly access to your friends. You
don’t even need to define a single reference in the user table! I
haven’t used it myself yet, but I believe you’ll get access to the
friends as an array :-

my_user = User.find(:first)
my_user.users

(I may be wrong!)

Ben

I have done a similar thing, and I created a friendship model for this.

The main reason is that in my system a friendship goes through multiple
stages. One user initiates a friendship request or invite, and the
other user either accepts (establishes a friendship) or rejects the
offer. Then at any time, one user might terminate the friendship. I
feel there is enough information here to warrant another model, and a
few columns in the friendship table.

I always query this model from the perspective of the active user (I
provide the user_id as a query condition), which avoids having to deal
with queries that include the user table twice. Then again, I’m kind of
a newbie, and maybe avoiding the problem is not your preference. :slight_smile:

I don’t have my code on me, but I hope this is a little helpful.

Chris