HABTM to HMT, whither BT?

I’m not positive I’m asking the right question, but based on tonight’s Imposter Syndrome talks at boston.rb, I’m forging ahead…

I often see has_many :through recommended over has_and_belongs_to_many. I understand the reasoning: usually the relationship has (or will have) additional attributes that need to be represented.

It feels like the same logic for avoiding HABTM should apply to belongs_to. I have a CaseFile that belongs_to a health-care Practitioner. If the CaseFile had multiple Practitioners (a HABTM relationship), the wisdom would advise me to use HMT from the start, since I’ll eventually need attributes on the relationship. By the same logic, I should skip the belongs_to phase and use HMT for the inevitable relationship attributes.

Is there some difference between the two cases, or have I been missing all the blog posts recommending HMT over BT?

Interesting. I had never thought to follow that argument through to belongs_to. I believe you’d actually want to compare belongs_to and has_one :through because in those cases you want there to be a single related object.

I have a couple of immediate reactions:

  1. In the case of HABTM vs HMT, you will be using a join table for lookups in either case. If you took a BT and prematurely made it a HOT, you would be using that join table when it might not actually be giving you anything of value.

  2. In rails, has_one relationships don’t actually enforce that there is only a single related record. They just return the first one. You can add unique indexes to your join table to prevent this, but it’s another step.

  3. In the case of HABTM vs HMT, I find that there’s almost always something interesting that I can call that join model that would eventually tease out a better design. I can’t say that would be true of most of my BT relationships.

Preferring has_many :through instead of has_and_belongs_to_many based on the inevitable addition of attributes is one reason to prefer HMT over HABTM, but it’s not the only reason.

Personally, the reason I greatly prefer it is that you give a name to the concept of the two models being joined. Giving the concept a name has multiple benefits, including being able to talk about every piece by the same name the program itself uses, not having important data structures be assumed and hidden and semi-magical, and knowing what’s going on because you can see the thing you’ve named. While it’s still a complex join, having given it a name makes it more visible. Basically, has_many :through has all the upsides of has_and_belongs_to_many with none of the downsides. That it allows you to add attributes is icing (though very tasty icing).

On the other hand, belongs_to isn’t guaranteed to turn into a one-to-many relationship, and you’re usually prematurely adding features and complexity to assume it will turn into one, so it wouldn’t be worth adding the complexity of managing a many-to-many relationship without actually needing one until the story comes up.

Does that make sense? That kind of thing feels right to me, but I never know if I’ve explained it well. :smile: