Here''s the basic situation class Person < ActiveRecord::Base acts_as_tree belongs_to :hair_color validates_presence_of :name end class HairColor < ActiveRecord::Base validates_presence_of :name end What I want to achieve: I need another association on Person that returns only the red-haired children. In my special case[*] it has to be an association, an association extension, named scope or similar won''t do. In particular, this association has to work when listing all persons and their red-headed children and possibly with a filter condition. A first stab looks like this class Person < ActiveRecord::Base ... has_many :redheads, :class_name => ''Person'', :foreign_key => :parent_id, :include => :hair_color, :conditions => "hair_colors.name = ''red''" end This works indeed for a case like this p = Person.find(:first) p.redheads however, it doesn''t work for parents = Person.find(:all, :include => :redheads) In that case, the secondary assocation (redheads.hair_color) doesn''t even seem to be included. Adding it manually like this parents = Person.find(:all, :include => [:redheads, :hair_color]) doesn''t help because the "scoping" is wrong: hair_color is joined on the parents, not the children. So, is there a way to make ActiveRecord do what I need without resorting to hand-written SQL? Michael [*] I already have the infrastructure to display and filter lists of objects with associated objects *one-level* deep. E.g., for a list of persons I could define a column { :column => ''hair_color.name'', :title => ''Hair color'' }. I''d like to specify a column such as { :column => ''redheads.name'', :title => ''Redheads'' }. -- Michael Schuerig mailto:michael-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org http://www.schuerig.de/michael/ --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
What about Red-Headed step children? sorry, couldn''t help it --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On 20 May 2008, at 17:21, Michael Schuerig wrote:> > however, it doesn''t work for > > parents = Person.find(:all, :include => :redheads) > > In that case, the secondary assocation (redheads.hair_color) doesn''t > even seem to be included. Adding it manually like this > > parents = Person.find(:all, :include => [:redheads, :hair_color])parents = Person.find(:all, :include => {:redheads => :hair_color}) ? Fred>--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
What about 2 steps @parent_ids = find(:all, :conditions => "hair_colors.name = ''red''"} @red_head_parents = find(:all, :conditions => ":id IN @parent_ids.uniq''"} I prolly mucked the syntax, but ... On May 20, 9:52 am, Frederick Cheung <frederick.che...-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:> On 20 May 2008, at 17:21, Michael Schuerig wrote: > > > > > however, it doesn''t work for > > > parents = Person.find(:all, :include => :redheads) > > > In that case, the secondary assocation (redheads.hair_color) doesn''t > > even seem to be included. Adding it manually like this > > > parents = Person.find(:all, :include => [:redheads, :hair_color]) > > parents = Person.find(:all, :include => {:redheads => :hair_color}) > ? > Fred > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
lets try that again redheads = Person.find(:all, :conditions => "hair_colors.name ''red''"} parent_ids = redheads .inject([]) do {|parent_list, redheads.parent_id| parent_list<<redheads.parent_id} red_head_parents = Person.find(:all, :conditions => ":id IN parent_ids''"} And I still prolly mucked it up --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On Tuesday 20 May 2008, Frederick Cheung wrote:> On 20 May 2008, at 17:21, Michael Schuerig wrote: > > however, it doesn''t work for > > > > parents = Person.find(:all, :include => :redheads) > > > > In that case, the secondary assocation (redheads.hair_color) > > doesn''t even seem to be included. Adding it manually like this > > > > parents = Person.find(:all, :include => [:redheads, :hair_color]) > > parents = Person.find(:all, :include => {:redheads => :hair_color}) > ?No, unfortunately not. I have a test dataset with 20 persons -- 4 parents + 16 children -- and a "random" assignment of hair colors.>> ps = Person.find(:all, :include => { :redheads => :hair_color }) >> ps.map { |p| p.redheads.map(&:hair_color).map(&:name) }=> [["black", "black", "blonde", "brown"], ["brown", "black", "red", "blonde"], ["blonde", "red", "brown", "brown"], ["brown", "black", "brown", "blonde"], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []] When I include the parent''s hair color, too, the result deteriorates>> ps = Person.find(:all, :include => [:hair_color, { :redheads=> :hair_color }])>> ps.map { |p| p.redheads.map(&:hair_color).map(&:name) }=> [[], [], [], ["brown", "black", "brown", "blonde"], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []] I''m not too fond of dissecting the generated SQL and especially why it was generated like that. From a somewhat superficial vantage point I''d say that the cause of the trouble lies with joining at the correct level, that is children, not parents. IIRC, the association code was slated for a thorough revision for Rails 3.0, I may just wait for it. Michael -- Michael Schuerig mailto:michael-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org http://www.schuerig.de/michael/ --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On Tuesday 20 May 2008, Ruby Freak wrote:> lets try that again > > redheads = Person.find(:all, :conditions => "hair_colors.name > ''red''"} > parent_ids = redheads .inject([]) do {|parent_list, > redheads.parent_id| parent_list<<redheads.parent_id} > red_head_parents = Person.find(:all, :conditions => ":id IN > parent_ids''"} > > And I still prolly mucked it upYes, on two counts. First, I''m not concerned with red-haired parents, but with their children. Second, I want to retrieve *all* parents with their red-haired children (if any) included. As all this is going to be displayed in a list with optional filter conditions, I may need to filter by the parent''s name or hair color as well as by a child''s name. Just consider the case where you have a paginated list of all people in your db and you want to filter it down to only the red-haired people who have a red-haired child named John. Michael -- Michael Schuerig mailto:michael-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org http://www.schuerig.de/michael/ --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On 20 May 2008, at 19:05, Michael Schuerig wrote:> > On Tuesday 20 May 2008, Frederick Cheung wrote: >> On 20 May 2008, at 17:21, Michael Schuerig wrote: >>> however, it doesn''t work for >>> >>> parents = Person.find(:all, :include => :redheads) >>> >>> In that case, the secondary assocation (redheads.hair_color) >>> doesn''t even seem to be included. Adding it manually like this >>> >>> parents = Person.find(:all, :include => [:redheads, :hair_color]) >> >> parents = Person.find(:all, :include => {:redheads => :hair_color}) >> ? > > No, unfortunately not. I have a test dataset with 20 persons -- 4 > parents + 16 children -- and a "random" assignment of hair colors. > >>> ps = Person.find(:all, :include => { :redheads => :hair_color }) >>> ps.map { |p| p.redheads.map(&:hair_color).map(&:name) } > => [["black", "black", "blonde", "brown"], > ["brown", "black", "red", "blonde"], > ["blonde", "red", "brown", "brown"], > ["brown", "black", "brown", "blonde"], [], [], [], [], [], [], [], [], > [], [], [], [], [], [], [], []] > > When I include the parent''s hair color, too, the result deteriorates >Ah yes, conditions on :include are a bit iffy and often give unexpected consequences. Rails 2.1 has a rewrite of eager loading but it may not help you Could you do it the otherway round i.e. something like red_color.find :people, :include => :parent That gives you all redheads with their parents. Then (can''t think of a better verb) transpose/invert this to have it by parent. This may be one of those times when writing some grungy sql is the way forward. Fred>>> ps = Person.find(:all, :include => [:hair_color, { :redheads > => :hair_color }]) >>> ps.map { |p| p.redheads.map(&:hair_color).map(&:name) } > => [[], [], [], ["brown", "black", "brown", "blonde"], [], [], [], [], > [], [], [], [], [], [], [], [], [], [], [], []] > > I''m not too fond of dissecting the generated SQL and especially why it > was generated like that. From a somewhat superficial vantage point I''d > say that the cause of the trouble lies with joining at the correct > level, that is children, not parents. IIRC, the association code was > slated for a thorough revision for Rails 3.0, I may just wait for it. > > Michael > > -- > Michael Schuerig > mailto:michael-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org > http://www.schuerig.de/michael/ > > >--~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
On Tuesday 20 May 2008, Frederick Cheung wrote:> Could you do it the otherway round i.e. something like > red_color.find :people, :include => :parent > That gives you all redheads with their parents. Then (can''t think of > a better verb) transpose/invert this to have it by parent.No, that doesn''t work because I want to list *all* persons but specifically include the red-haired children in the list. A more practical reason is that it does not fit with my current infrastructure that nicely handles all the easier cases. Incidentally, I''m not preoccupied with redheads, apart from myself having a hair color in that general direction. It''s just that this somewhat contorted example perfectly fits my real problem. Michael -- Michael Schuerig mailto:michael-q5aiKMLteq4b1SvskN2V4Q@public.gmane.org http://www.schuerig.de/michael/ --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe@googlegroups.com For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---
frioux-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org
2008-May-21 05:37 UTC
Re: Finding parents with red-haired children?
> No, that doesn''t work because I want to list *all* persons but > specifically include the red-haired children in the list. A more > practical reason is that it does not fit with my current infrastructure > that nicely handles all the easier cases. > > Incidentally, I''m not preoccupied with redheads, apart from myself > having a hair color in that general direction. It''s just that this > somewhat contorted example perfectly fits my real problem.Did you ever figure this one out? I in a similar situation. Basically I am trying to fake inheritance with a belongs_to relationship, which means that if I want to search by any of the columns that come from the "parent" object I have to do it outside of the database. Anyway, if I figure anything out I''ll note it here. -fREW --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk-unsubscribe-/JYPxA39Uh5TLH3MbocFFw@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en -~----------~----~----~----~------~----~------~--~---