Is it possible to retrieve the child elements in a has_many association into a hash based on one of their properties?
For example, imagine a menu that has a single dish for each day:
class Menu
has_many :dishes
end
and
class Dish
belongs_to :menu
end
Dish has a key, day, which is one of either monday, tuesday etc. Is there some way to set up the has_many association such that Menu.dishes returns a hash similar to {:monday => 'spaghetti', :tuesday => 'tofu', ... }?
Sure. Something like this should suffice (assuming e.g. “spaghetti” is stored in a column called
food).So what’s happening here is that in
Dishtheby_dayscope returns only two columns,dayandfood. It still, however, returnsDishobjects rather than a Hash (because that’s what scopes do), so we define a class method,by_day_hashwhich takes that result and turns it into a Hash.Then in
Menuwe definedishes_by_daywhich just calls the method we made above on the association. You could just call thisdishesbut I think it’s better to keep that name for the original association since you might want to use it for other things later on.Incidentally (optional stuff below, skip for now if your eyes have glazed over), I might define
by_day_hashlike this instead:…This way you still get the full
Dishobject when you call e.g.by_day_hash["monday"]but theto_smethod means you can just drop it into a view like<%= @menu.dishes_by_day["monday"] %>and get “Spaghetti” instead of#<Dish day: "monday", food: "Spaghetti">.Finally, you might also notice I used
HashWithIndifferentAccess.newinstead of{}(Hash). HashWithIndifferentAccess is a class provided (and used everywhere) by Rails that is identical to Hash but lets you do either e.g.some_hash["monday"]orsome_hash[:monday]and get the same result. Totally optional but very handy.