问题
I have an admittedly ugly query to do, to find a particular role related to the current role. This line produces the correct result:
@person_event_role.event_role.event.event_roles.
joins(:mission_role).where(:mission_roles => {:title => 'Boss'}).
first.person_event_roles.first.person
(You can infer the associations from the plurality of those calls)
The only way to get this information requires a ton of knowledge of the structure of the database, but to remove the coupling... It would require filling in a bunch of helper functions in each step of that chain to give back the needed info...
回答1:
I think the thing to do here is to create the helper functions where appropriate. I'm unclear what the beginning of your association chain is here, but I'd probably assign it a method #event
that returns event_role.event
. From there, an event
has an #boss_role
, or whatever makes sense semantically, and that method is
event_roles.joins(:mission_role).where(:mission_roles => {:title => 'Boss'}).first
Finally, also on the Event
model, there's a #boss
method, which gets
boss_roles.first.person_event_roles.first.person
So, your original query becomes
@person_event_role.event.boss
Each leg of the chain is then self-contained and easy to understand, and it doesn't require the beginning of your chain to be omniscient about the end of it. I don't fully comprehend the full reach of these associations, but I'm pretty sure that just breaking it into three or four model methods will give you the clean reading and separation of concerns you're looking for. You might even break it down further for additional ease of reading, but that becomes a question of style.
Hope that helps!
The following is by the original questioner
I think I followed this advice and ended up with:
@person_event_role.get_related_event_roles_for('Boss').first.filled_by.first
#person_event_role:
def get_related_event_roles_for(role)
event.event_roles_for(role)
end
def event
event_role.event
end
#event:
def event_roles_for(role)
event_roles.for_role(role)
end
#event_role:
scope :for_role, lambda {|role| joins(:mission_role).where(:mission_roles => {:title => role})}
def filled_by
person_event_roles.collect {|per| per.person}
end
来源:https://stackoverflow.com/questions/8950122/how-do-i-apply-the-law-of-demeter-to-this