I have an ActiveRecord class with a reflexive association (note : class names are redacted for non-disclosure reasons) :
class Thing < ActiveRecord::Base belongs_to :parent, class_name: 'Thing' has_many :children, class_name: 'Thing', foreign_key: :parent_id scope :children, ->{ where(arel_table[:parent_id].not_eq(nil)) } end I want to get all children, left outer joined to their parent, with an additional condition on the parent if it's present, while still eager-loading the parent.
Usually in this case i do something like :
Thing.includes(:other_thing).merge(OtherThing.some_scope) But it's not possible in this case : as this is a self-join, if I merge a scope from Thing the condition will apply to the children things, not the parents.
I tried to do this in raw SQL :
scope :some_scope, ->{ children.joins(<<-SQL).references(:parent) LEFT OUTER JOIN things AS parents ON things.parent_id = parents.id AND parents.some_field IN ('foo', 'bar') SQL } The query is OK, but it seems that the parent does not get eager-loaded (n+1 queries when trying to map(&:parent) on this scope).
For now, my more-or-less working solution is to use a sub query (plucking ids that match the parent condition, then selecting children with parent_id IN this set), but I'd like to know if there is a more appropriate / elegant one.