Workaround for has_many :through overriding the :select clause

Posted by Tim Connor Mon, 15 Jun 2009 22:30:00 GMT

As I mentioned earlier a named_scope select clause will get overridden in a has_many :through.

class Grandparent
  has_many :grandchildren, :through => :children
end

class Grandchild
  named_scope :summed_ages_by_gender, :select => "SUM(age) as age", :group => :gender
end

Grandparent.first.grandchildren.summed_ages_by_gender
#does not do what you want, because the through overrides the select

If you have a case where this isn’t acceptable, such when you have a complicated aggregate select that you would like to call on a has_many through, there is an ugly work-around. You can recreate the has_many :through, with joins in a scope on the child model, then return that in a method of the grandparent.

class Grandparent
  def grandchildren
     Grandchild.grandchildren.scoped({:conditions => ['grandparents.id = ?'], id})
  end
end

class Grandchildren
  named_scope :summed_ages_by_gender, :select => "SUM(age) as age", :group => :gender
  named_scope :grandchildren, :joins => ['JOIN parents ON grandchildren.parent_id => parents.id', 'JOIN grandparents ON parents.grandparents_id = grandparents.id']
end

Grandparent.first.grandchildren.summed_ages_by_gender
#should work

Obviously I would not advise using this as a relationship model – it was one I just threw together for elucidation. And I haven’t run this exact code, but I have run the code it is a dummied up copy of, with great success.

Maybe I’ll try and come up with a patch to fix the original problem, but the through select logic is probably some of the most edge-case ridden in AR associations, so I am not sure how easy it would be.

Update: I made a ticket with a patch for the failing test, at least.

Leave a comment

Comments