Nesting your has_many :through relationships

Let’s say you’re creating a site where people can track their memberships in various store clubs – from grocery store loyalty cards, to memberships to Sam’s or CostCo. People and Stores have a many-to-many relationship called a Membership. Stores also have sales, and you want people to be able to manage all sales at all of their stores easily.

The Problem

You’d like to be able to say @member.sales, but there’s a problem – Rails doesn’t support daisy-chaining associations the way we’d like. Here’s how we want to setup our associations:

While everything looks good from a data modeling perspective, there’s one issue – our member model isn’t allowed to daisy-chain assocations, so we can’t get to our sales easily. A call to @member.sales gives us this:

The Solution

In comes Ian White’s nested_has_many_through plugin, which does exactly what you’d think Rails does already. Without changing the way you create associations, this plugin “just works” out of the box. Nothing to include in models or config files. Here’s how you install it:

Now run @member.sales and you get what you’d expect – a list of all sales that a member is entitled to attend. You can nest even deeper if you like, but I offer this word of caution. Nested has_many :through associations are like the most precious liquid on earth: Captain Morgan’s spiced rum. Enjoy in moderation :)

Epilogue

I’ve created a full rails app on GitHub (View the Source Code) so you can download and play around with it. There are “before” and “after” tags, so you can see how the app reacts with and without the plugin. It also has Shoulda tests.