Reputation: 2554
I would like to understand the most efficient way to flatten some has_many associations, and subsequently get the sum of some attribute on the child associations. Suppose you have the following data structures:
class Restaurant < ActiveRecord::Base
has_one :address
has_many :menu_items
end
class Address < ActiveRecord::Base
belongs_to :restaurant
end
class MenuItem < ActiveRecord::Base
belongs_to :restaurant
end
Say that MenuItem has the attribute "cost", and Address has the attribute "zip_code". What I would like to do is maybe find all restaurants in the zipcode '10101' and get the sum of their menu item's cost attributes. Say that I want to be able to show the average cost of restaurants' offerings in an area.
I think there are quite a few brute force-y ways to do this, but I know there should be something better. For example, in C#/LINQ if I had a similar set of data structures it would be easy to write:
var sum=restaurants.Where(r => r.zip_code==10101).SelectMany(r => r.MenuItems).Sum(mi => mi.Cost);
The best I have come up with, but that feels wrong to me, is:
def thing_I_dont_know_how_to_do
find_zip=Address.where(:zip_code => zip_code)
restaurants=Restaurant.joins(:address, :menu_items).merge(find_zip)
restaurant_ids=restaurants.map(&:id)
sum=MenuItems.sum(:cost, :conditions => {:restaurant_ids => venue_ids})
end
Can anyone help me improve upon this?
Upvotes: 0
Views: 786
Reputation: 24340
You can do it with a single SQL request which selects all the menu items of restaurants in zip code 10101, and sums all their cost:
MenuItem.joins(restaurant: :address).where(addresses: { zip_code: '10101' }).sum('cost')
Upvotes: 2