How to get the children of a *collection* of parent objects?

I frequently need to do something like the following (pseudo-code):

Company.find(:conditions => ["city == ‘Sandusky’]).employees

This of course doesn’t work because Company.find returns an array of
companies, and ‘employees’ is not a defined method for Array.

But you know what I mean. Is there a canonical way of doing this that
doesn’t involve lots of manual iterating? It becomes especially critical
as the find becomes complicated.

And what about if I want distinct employees from the above example
(assume they’re part timers who could work at many companies)?

Thanks!

/afb

I should clarify that I didn’t define a relationship (has-many or HABTM)
in the above example, since ideally there would be a solution that works
in either case.

/afb

I frequently need to do something like the following (pseudo-code):

Company.find(:conditions => ["city == ‘Sandusky’]).employees

If i understood it well, you have two tables, Companies and employees,
and you want to get all the employees from several companies given some
conditions.

ActiveRecord makes it pretty-straight forward to get this.

Employee.find(:all, :include=>:company,
:conditions=>“companies.city=‘Sandusky’”)

If you want to get unique results, you could use uniq over the resulting
array, but since we are using include, the array you are getting is
including the companies too; with a bit of mapping, we can just filter
that out.

Employee.find(:all, :include=>:company,
:conditions=>“companies.city=‘Sandusky’”).map{|e| e.attributes}.uniq

this way, you are converting the resulting array in an array with only
the attributes of Employee model, and now you can just use uniq to
remove any dupplicates.

Another approach in order to avoid the mapping would be not using
:include, but :join and :select, with the only “problem” that you have
to tell ActiveRecord how to join the tables and I would say is a bit
less idiomatic because you are in some way breaking the ORM pattern.
Also, if you are joining tables through a many to many relationship with
another table in the middle, the join could get tricky, so I’d recommed
to go with the :include/map solution.

regards,

javier

[email protected]

Employee.find(:all, :include=>:company,
:conditions=>“companies.city=‘Sandusky’”)

:include executes the default join, okay. Didn’t know that. Does that
work if your association is many-to-many using :through?

Employee.find(:all, :include=>:company,
:conditions=>“companies.city=‘Sandusky’”).map{|e| e.attributes}.uniq

And using map + uniq is something I have not seen before.

That’s very helpful, thanks!

/afb

Just in case I misled you. Actually uniq has nothing to do with “map”.

Right. Your clarification is very helpful. Thanks again!

/afb

:include executes the default join, okay. Didn’t know that. Does that
work if your association is many-to-many using :through?
include makes an outer join with the table described in the association
declaration (the has_many or has_one or whatever in the Model). All the
supported associations can be included, and since it’s an outer join,
you always get all the results for your main table and only the matching
rows for the included one

Employee.find(:all, :include=>:company,
:conditions=>“companies.city=‘Sandusky’”).map{|e| e.attributes}.uniq

And using map + uniq is something I have not seen before.
Just in case I misled you. Actually uniq has nothing to do with “map”.
Uniq takes an array and eliminates duplicates. Map takes an array and
returns a different array containing whatever we return in the block.

The reason for using map here is that the array returned by find was
including both the fields of Employee and Company, so you wouldn’t have
any duplicates and running uniq would do nothing. What we are doing is
using map to get a new array containing only the columns of Employee, so
now we can let uniq do its work and clean our list.

regards,

javier ramirez