What is the difference between the
has_and_belongs_to_many
and
has_many through
relationships? When and where to use which one?

- 25,981
- 23
- 80
- 125

- 43,139
- 57
- 169
- 274
8 Answers
As far as I can remember, has_and_belongs_to_many
gives you a simple lookup table which references your two models.
For example,
Stories can belong to many categories. Categories can have many stories.
Categories_Stories Table
story_id | category_id
has_many :through
gives you a third model which can be used to store various other pieces of information which don't belong to either of the original models.
For example
Person can subscribe to many magazines. Magazines can have many subscribers.
Thus, we can have a subscription model in the middle, which gives us a similar table to the earlier example, but with additional properties.
Subscriptions Table
person_id | magazine_id | subscription_type | subscription_length | subscription_date
And so on.

- 2,439
- 5
- 28
- 43

- 4,068
- 10
- 41
- 51
-
43note that the table needs to by named in alphabetical order i.e. categories_stories table as opposed to stories_categories - this is the convention that makes it work. – Will May 06 '10 at 13:33
-
Thanks, I've changed my post now – Dan May 06 '10 at 14:05
-
1why must they be alphabetical @Will? – ctilley79 Jun 26 '12 at 03:35
-
@ctilley79 that is the convention used. So when the association is set up it knows what table to look for – Will Jun 28 '12 at 18:59
-
@Will I'm getting the exact same thing. It will not include the additional attribute in writing to the database. My question has the create statement that active record is writing to the database. That might help – ctilley79 Jun 28 '12 at 19:21
-
@ctilley79 rails tries to figure out which join table to use, but you can overwrite that with the 'class_name' option – Brian Joseph Spinos Oct 28 '17 at 19:44
-
2The punch line here is that you will *always* end up needing to add attributes to your join table, sooner or later. Go ahead and use `has_many through:` from the beginning and save pain later. If it turns out you don't add attributes...you still have lost nothing. – David Hempy Aug 16 '19 at 14:34
The simplest rule of thumb is that you should set up a has_many :through relationship if you need to work with the relationship model as an independent entity. If you don’t need to do anything with the relationship model, it may be simpler to set up a has_and_belongs_to_many relationship (though you’ll need to remember to create the joining table in the database). You should use has_many :through if you need validations, callbacks, or extra attributes on the join model.

- 2,492
- 20
- 20
-
3I would also add that there are a lot of methods rails inserts to has_and_belongs_to_many and not to has_many :through. All of the methods like assigning a collection of values to the association, doesn't seem to show in the documentation for has_many :through http://guides.rubyonrails.org/association_basics.html#has_and_belongs_to_many-association-reference – e3matheus Jan 11 '12 at 19:01
My rule of thumb is, can I get by with a list of checkboxes here? If so, then it's a has-and-belongs-to-many (HABTM) association. If I need the checkbox to capture more about the relationship than simply yes/no it belongs, then use has_many :through
. HABTM is as simple as using the _ids method with a simple_form collection_check_boxes. has_many :through
often involves accepts_nested_attributes_for
.

- 25,981
- 23
- 80
- 125

- 5,274
- 1
- 20
- 11
From my experience it's always better to use has_many: through
because you can add timestamps to the table. Many times while debugging some ActiveRecord
objects that are connected through HABTM, I was missing created_at
, updated_at
timestamps to get the clue what actually happened.
So keep in mind that it can help you to debug, investigate an issues with the data relations in the context of the time, because without it you are "blind" when relations were created or updated.

- 1,267
- 1
- 22
- 30
Many of the answers clarify that you should use has_and_belongs_to_many
vs. has_many through:
if you will not need any extra data or validations on the join table.
However, beware of taking this approach. In the early stages of application development, it is nearly impossible to know what extra features or validations you may need in the far future of your project's lifecycle. If you decided to use has_and_belongs_to_many
, and want to add one simple datapoint or validation 2 years down the road, migrating this change will be extremely difficult and bug-prone. To be safe, default to has_many :through

- 97
- 1
- 3
-
2Can you explain why this would be dangerous and bug prone? a HABTM is _the same_ as a has_many :through, just without the model. You can very gracefully convert a HABTM into a though. – grepsedawk May 10 '19 at 22:39
-
1Here's a good answer to your question, @grepsedawk : https://www.flatironschool.com/blog/why-you-dont-need-has-and-belongs-to-many – David Hempy Aug 16 '19 at 14:31
You should use has_many :through if you need validations, callbacks, or extra attributes on the join model.

- 316
- 2
- 3
The simplest rule of thumb is that you can go with has_many :through
relationship if you need to work with the relationship model as an independent entity.
If you don't need to do anything with the relationship model, it may be simpler to set up a has_and_belongs_to_many relationship
(though you'll need to remember to create the joining table in the database).
You should use has_many :through
if you need validations, callbacks, or extra attributes on the join model.

- 777
- 8
- 14
Rails offers two different ways to declare a many-to-many relationship between models. The first way is to use has_and_belongs_to_many, which allows you to make the association directly:
The second way to declare a many-to-many relationship is to use has_many :through. This makes the association indirectly, through a join model:
You should use has_many :through if you need validations, callbacks, or extra attributes on the join model.