views:

26

answers:

2

I am trying to build a relationship model between users. A user can either initiate a relation, or receive a relation from another user. Therefore, the relations table in the db has the foreign keys "initiator_id" and "recipient_id".
Now, I can figure what relations the user initiated or received using the following associations:

has_many :initiated_relations, :foreign_key => :initiator_id, :class_name => 'Relation', :dependent => :destroy
has_many :received_relations,  :foreign_key => :recipient_id, :class_name => 'Relation', :dependent => :destroy

What I am trying to do, is build an association that will fetch me all relations that belong to a user (either initiated or received). Trying the following does not work, and complains about the lack of "user_id" field:

has_many :relations, :conditions => 'recipient_id = #{id} or initiator_id = #{id}'

How can I create an association that is solely based on the conditions field, without looking for the default foreign_key? Or is there perhaps a completely different approach to solving this?

+1  A: 

Well, I can think of using finder_sql for that:

has_many :relations, :finder_sql => 'select * from relations right outer join users
    on relations.recipient_id = #{id} or relations.initiator_id = #{id}'

Apart from that, you can just write a method that will return a united array of the two relations associations', but you will lose the advantage of an association interface (phew).

Perhaps someone will come up with a better solution.

neutrino
I already tried using finder_sql, however if there is any other way to achieve this I would prefer that, because with finder_sql I lose all functionality of associations. e.g: I can't do `user.relations.find(:all, :conditions => {:confirmed => true})` or any other such function. Thanx for your input though, much appreciated.
Faisal
+1  A: 

From your comments to @neutrino's answer I understand, that you only need this "releation" for read only operations. If you're on Rails 3 you can utilize the fact, that it uses lazy fetching. The where() method returns ActiveRecord::Relation object, which you can later modify. So you can define a method like this:

def User < ActiveRecord::Base
  def all_relations
    Relation.where("initiator_id => ? OR recipient_id = ?", id, id)
  end
end

And then you can do:

User.all_relations.where(:confirmed => true).all
Matt
@Matt: This seems like a very elegant solution, and yes, I only want this relation for read-only purposes. However, I am not using Rails 3, so this won't work for me :(. +1 for the great answer though :).
Faisal