Why I Rarely Use HABTM «

Code: , , , ,

I was chatting with Kori Roys about database design and I mentioned offhandedly that I almost never use has_and_belongs_to_many in Rails. Kori’s ears perked up and he asked why that is.

I’ve been pondering, and it’s related to my old Rules Of Database App Aging post, which has aged well (unfortunately). One more thing I’ve recognized is that those join tables between what I think of as two records very quickly pick up their own life.

To use the examples from that post, the guy who lives in one state and works in another needs to track what dates he started that relationship in each for taxes. The email going to multiple feeds needs different formatting applied for each. A state’s caucus may refer back to the results of the previous caucus to determine ballot order or election fund matching. Things with multiple categories may care about the order their categories are displayed in.

In all these cases and more, it’s plausible for that relationship to become a domain object in its own right (most often with timestamps and active/inactive flags, in my experience). It happens often enough that I find myself almost never using the implicit relationships provided by has_and_belongs_to_many in favor of new, explicitly-named objects with two belongs_to/has_many relationships. These can take on data and responsibilities in a natural way as needed and make the app easier to talk about.


  1. At first, I had thought you were talking about in the database and I was wondering why… then I realized you specified “in rails” and all became clear. lol

    I’m assuming you usually work with has_many :through, correct?

  2. Yes, I’ll typically have

    class Author < ActiveRecord::Base
      has_many :authorships
      has_many :articles, :through => :authorship
    class Article < ActiveRecord::Base
      has_many :authorships
      has_many :authors, :through => :authorship
    class Authorship < ActiveRecordBase
      belongs_to :author
      belongs_to :article

Leave a Reply

Your email address will not be published.