Forum: Ruby on Rails Symmetric relationships

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Chef vom Dienst (Guest)
on 2007-06-10 23:13
(Received via mailing list)
Hi,
I'm building an application where you can have friends like in
myspace. Only if two people agree to be friends, a friendship relation
should be established. If they agreed, it should be an undirected (aka
symmetric, bidirectional)
graph.
I don't want to keep two entries for each friendship like in the
following table:
table friendships
parent | child
user1 | user2
user2 | user1

I hope you understand what I mean. I want that if anybody of the two
friends quit friendship, the relationship between the two also gets
deleted.

Thanks.
Steve R. (Guest)
on 2007-06-11 19:45
What type of queries do you need to be able to do after this
relationship is set up? For example

Do Pam and Jeff have a friendship?
List all the friends of Pam?
List all the people who are not friends of Pam or Jeff?

The best solution will depend on how you want to get to the data.

steve
Chef vom Dienst (Guest)
on 2007-06-11 22:44
(Received via mailing list)
Most basically I just want to query the friends of Pam.
If Pam and Jeff are friends, i want to get
Pam as friend of Jeff
and Jeff as friend of Pam.

For this I would have to keep two database entries for each
friendship, like in the following example:
user_id | friend_id
id_of_pam | id_of_jeff
id_of_jeff | id_of_pam

I'd like to do it with one, but I don't think there is an elegant
solution, or is it?

A wish of mine also would be to get the shortest connection between
person A and person B, like in xing.com (single pair shortest path
problem in graph theory), but I have no idea how to do that, and it's
not a necessity.

Etherway, not having to keep two entries for each friendship (then you
had also to monitor when a friendship gets deleted to also delete the
other way round) would be favorable for this problem too.

On Jun 11, 5:45 pm, Steve R. <removed_email_address@domain.invalid>
Steve R. (Guest)
on 2007-06-12 00:36
> Most basically I just want to query the friends of Pam.
> If Pam and Jeff are friends, i want to get
> Pam as friend of Jeff
> and Jeff as friend of Pam.

If you only want to be able to say is Pam a friend of Jeff then you
could assign each user a unique prime number and store the multiple of
the primes in a separate 'friendship' table. But that won't help you
list all the friends of Pam (unless you don't mind iterating over every
entry in the table).

So, what exact queries do you want to be able to do?

steve
Chef vom Dienst (Guest)
on 2007-06-12 01:46
(Received via mailing list)
Thanks for your advice, but unfortunately I would also like to select
all friends of Pam at once.

On Jun 11, 10:36 pm, Steve R. <rails-mailing-l...@andreas-
Steve R. (Guest)
on 2007-06-12 15:31
> Thanks for your advice, but unfortunately I would also like to select
> all friends of Pam at once.

I can't think of a way of doing this with only one table entry. I'm
surprised because I thought I would be able to. It's an interesting
problem and I'll pass it on to some colleagues.

steve
Steve R. (Guest)
on 2007-06-17 16:34
No progress I'm afraid.

You are aware that what you want is handled by Rails using
has_and_belongs_to_many relationships? But it does use two entries in a
table for each relationship, you just don't have to actually handle the
table yourself.

steve
Chris T. (Guest)
on 2007-06-26 02:38
(Received via mailing list)
Steve R. wrote:
>
>
I did this in the following way (YMMV):

class Person << AR::B
  has_many :relation_tos,
    :class_name => 'Relationship',
    :foreign_key => 'related_from'
  has_many :relation_froms,
    :class_name => 'Relationship',
    :foreign_key => 'related_to'
  has_many :related_tos,
    :through => :relation_tos,
    :source => :relatee,
    :select => "modtypes.*, relationships.relationship_type,
relationships.notes" # This gets the key join table details as well
  has_many :related_froms,
    :through => :relation_froms,
    :source => :relator,
    :select => "modtypes.*, relationships.relationship_type,
relationships.notes" # This gets the key join table details as well

  def related_types
    related_froms.find(:all) + related_tos.find(:all)
  end

The downside is, there's two db queries to get the related people. I did
this ages ago, in my early days on Rails, so haven't really looked to
see whether it can be improved.

Hope this helps

Chris
p.s. It's not really a person class, since that sort of relationship
isn't reflexive -- e.g. think of uncle-nephew relationship.

--
----------------------------
http://autopendium.com
Stuff about old cars
wolfmanjm (Guest)
on 2007-07-04 04:17
(Received via mailing list)
How about using sql? avoiding habtm or hm :through?

so given a table

table friends
  int inviter_id
  int Invitee_id
  bool accepted

And only one entry per friendship.

then find all friends using...

find_by_sql(
 'SELECT p.* FROM people p, friends f WHERE f.accepted = 't' AND
( (f.invitee_id = #{id} AND p.id = f.inviter_id) OR (f.inviter_id =
#{id} AND p.id = f.invitee_id) )'
)

I haven't tested this, but seems it should work in both directions.
This topic is locked and can not be replied to.