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.