You kids and your fancy ActiveRecord stuff. You’re having all the fun
while us geezers are writing complex JOINS by hand. Whee!
Wondering if anyone has reached a more elegant solution to this sort
of has_many :through association.
Say I’ve got Jobs, Participations, Roles and Users.
A Job has_many Users through Participations.
A Participation belongs_to a Role, User, and Job.
One type of role is a “Candidate”, represented as a Role object
Role::CANDIDATE.
To create a custom AR collection like job.candidates, I’ve implemented
the following:
(sorry, pastie is broken right now)
class Job
has_many :participations
has_many :users, :through => :participations
has_many :candidates, :through => :participations,
:source => :user,
:conditions => [“role_id = ?”,
Role::CANDIDATE.id]
end
So job.candidates yields:
SELECT “users”.* FROM “users” INNER JOIN participations ON users.id =
participations.user_id WHERE ((“participations”.job_id = 28) AND
((role_id = 6)))
And job.candidates << my_user yields:
INSERT INTO “participations” (“job_id”, “updated_at”, “role_id”,
“user_id”, “created_at”) VALUES(28, ‘2008-07-10 17:52:55.031711’,
NULL, 11, ‘2008-07-10 17:52:55.031711’)
It would be great if AR would, for through relationships with
conditions, automatically take the condition clause and be smart
enough to intelligently supply the id value during the INSERT. In
other words, I need that NULL value to be ‘6’.
My first approach to this problem was to try using a :before_add
function, like so:
:before_add => Proc.new {|job, user| #would love to do it here}
But :before_add only receives a reference to the local and foreign
object, eg the Job and the User. It would be great if somehow I could
get a reference to the object in the join (Participation) such that:
:before_add => Proc.new {|job, participation, user| participation.role
= Role::CANDIDATE}
I realize I can create a method add_candidate(user) and manually do
this stuff… but has anyone encountered a similar situation and
reached an elegant solution?
Thanks for taking the time to read this.