May 11, 2015 by Daniel P. Clark

HABTM; You Don’t Need It

My point: “For any valid use of implementing a has_and_belongs_to_many there is an equally valid way to implement it without it.”

A few reasons: Rails had changed both the way it worked and removed it from reflections for a brief period (Rails version 4.1.0 and 4.1.1).  Also the preferred implementation is to use has_many :through.  See this former Rails Issue #14682 and the subsequent Pull Request #15210 on the details.  The reflection was added back in Rails 4.1.2, but this doesn’t seem to be desired for access as a public api (source).

But I’d like to go even further and say you can keep it simpler, get the job done, and be able to manage your data far more easily with just using the basics.

Let’s look at an example from from Kick-Off: First Rails 4 Application with HABTM Association.  He uses an example where a person HABTM communities and a community HABTM persons.

Now whereas this is true in a sense that they both have and belongs to many of the other, it leaves the relationship of how this is true as unknown.  For example, as person can belong to a community as a member, owner, founder, etc.  This is a perfect place to use a has_many :through and then define your members/founders as such.  Then when you select the community.founders it will give a results that makes sense by the context it is given.

Now you can even go a step further away from HABTM, if you wanted to, and just create a membership table.  Create a polymorphic membership table so you can define memberships for any other Rails object you’d like.

The advantages of polymorphic relations are countless.  If you are unfamiliar with polymorphic relations I’ve given a thorough post on it here: Rails Polymorphic Associations .  Polymorphic records can be assigned to any ActiveRecord model; even itself.  That’s right I’ve written an example model here: Coffee Model and a test to verify the relationship is valid here: Minitest Spec Example.  And everything passes all GREEN ^_^.  So polymorphic models are your best friend.

Since a person is always the one implied when a membership is involved here we’ll create a field person_id.  But other than that the polymorphic membership model will determine what the membership belongs to.

Then update the models

Then you can create memberships on your community rather simply.  First we’ll create a person and a community, then the membership with both.

Look ma!  No HABTMs!  In the last line I show looking up memberships for the community.  You can do the same thing for a person object to find the memberships a person belongs to e.g.) Person.first.memberships

Code is easier to maintain if you stick to what is simple and basic.  I’ve come to appreciate this over time as I’ve written a library that’s tied heavily into all this relationship-workings (PolyBelongsTo).  I hope I can save many people from headaches by doing things the hard way… even unknowingly.


I believe I’ve made my point on HABTM.  If you can see a counter-argument to what I’ve presented here I’d love to hear about it.  Often times we over-think things and overcomplicate them.  When the best thing to do is often to take a step back, simplify it, and keep it simple.

Please feel free to comment, share, subscribe to my RSS Feed, and follow me on twitter @6ftdan!

God Bless!
-Daniel P. Clark

Image by Len Matthews via the Creative Commons Attribution-NonCommercial-ShareAlike 2.0 Generic License.

#belongs to#easy#habtm#has many#has_many_and_belongs_to#rails#simplify
0 0 vote
Article Rating
Notify of
Newest Most Voted
Inline Feedbacks
View all comments
7 years ago

Fixing HABTM by using Polymorphic Relations? Thanks, no thanks.

Daniel P. Clark
7 years ago
Reply to  Dev

The HABTM example gives no clear definition on the relation. Polymorphic relations are as flexible as you could need. If nothing else it’s recommended to use has_many :through rather than has_and_belongs_to_many. Or you can make a nonpolymorphic table memberships with person_id and community_id … it’s just a regular database table.

The biggest issue with HABTM is that you have to write a whole extra set of ways of handling relationships. It’s handled differently and requires additional code for its use case. While it would be much easier to use one uniform approach which permits a meta-programming friendly way of doing things.

My main point is simply that you don’t need to use HABTM and it’s not as well treated in Rails as other ways of implementing things.

What do you have against polymorphic relations?

Nathan Ladd
Nathan Ladd
7 years ago

HABTM has nice syntax with fixtures:

# persons.yml
communities: ruby, ios

# communities.yml

HABTM is the right fit for pure many to many join tables. It results in the least amount of complexity and the cheapest maintenance long term.

When you need more, it’s easy to switch to HM:T.

Daniel P. Clark
7 years ago
Reply to  Nathan Ladd

Thanks for your input! I did not know. I’d be very interested in learning more behind the statements you made of “least complexity” and “cheapest maintenance”. Are these based on not having a middle relational term? (such as membership) If so is that what makes it simpler/cheaper since there is “technically less” to deal with?