has_and_belongs_to_many Isn't Dead!

A few times over the past year, I’ve been describing a Rails has\_and\_belongs\_to\_many relationship and someone has piped up “Don’t use that, it’s deprecated!”

Wrong.

People are under the impression that HABTM relationships are deprecated because of the newer Has Many Through relationship. Both are good, and both have their place, but HABTM is still valid, vibrant, and useful!

HABTM is used when your join table is strictly a join table with nothing else[1]. As soon as you want more columns on that table, convert it to a has\_many :through relationship. Then you treat it as a full Model, adding validations, callbacks, and other columns.

So why is HABTM still a good thing? For one, not all many-to-many relationships need to be full models. Often it is just a simple link. If you aren’t sure, start simple. It is trivial to write a migration to convert to a has\_and\_belongs\_to\_many later.

There are also performance benefits to HABTM relationships. You don’t have to run callback chains or validations, and you don’t have to instantiate ActiveRecord objects for your join model (which is very slow)[2].

So use both, but don’t spend the time building full has\_many :through when you don’t need them. has\_and\_belongs\_to\_many is still good, and not going away.

[1] In the bad old days, you could have other columns on a HABTM table, but that part has been deprecated and removed, as detailed by this Stack Overflow post. People mis-read that and think HABTM is completely deprecated.

[2] Most of the time, you shouldn’t need to instantiate objects for has\_many :through either, but you will sometimes and that’s a performance hit.

Photo of Daniel Morrison

Daniel founded Collective Idea in 2005 to put a name to his growing and already full-time freelance work. He works hard writing code, teaching, and mentoring.

Comments

Add a Comment

Hmm...that didn't work.

Something went wrong while adding your comment. If you don't mind, please try submitting it again.

Comment Added!

Your comment has been added to this post. Please refresh this page to view it.

Optional. If added, we will display a link to the website in your comment.
Optional. Never shared or displayed in your comment.