In Rails, there are two main ways of creating many-to-many relationships between models:
- using a has_and_belongs_to_many association
- using has_many :through association
This is Quick tips, so let's cut to the chase.
This is the easiest way to establish a many-to-many relationship. It will create a database table to relate the two models (but not a third model to represent the relation).
Suppose you have two models that need to have a many-to-many relationship:
The first step is to write a migration, that (for this example) would look like this:
class AddHABTMForInstrumentsAndmusicians < ActiveRecord::Migration[6.0] def change create_table :instruments_musicians, id: false do |t| t.belongs_to :instrument t.belongs_to :musician end end end
If you run this migration it will generate the following table description in schema.rb:
create_table "instruments_musicians", id: false, force: :cascade do |t| t.bigint "instrument_id" t.bigint "musician_id" t.index ["instrument_id"], name: "index_instruments_musicians_on_instrument_id" t.index ["musician_id"], name: "index_instruments_musicians_on_musician_id" end
Now the only thing you need is to add the has_and_belongs_to_many line to each model, like this:
class Instrument < ApplicationRecord has_and_belongs_to_many :musicians end class Musician < ApplicationRecord has_and_belongs_to_many :instruments end
And we are done, that's all you need to create a has_and_belongs_to_many relationship.
Using has_many :through
The main difference between this option and the first one is that now a third model is created. Such model can contain things like custom behavior or validations, and it might be useful in many cases.
Going back to our example, for creating a has_many :through association we need to write a migration that creates a model that logically ties musicians and instruments, something like a songbook:
create_table :songbooks do |t| t.belongs_to :instrument t.belongs_to :musician t.string :title #we can add extra attributes if we want t.timestamps end
Now, we can add the associations to the models:
class Songbook < ApplicationRecord belongs_to :instrument belongs_to :musician end class Instrument < ApplicationRecord has_many :songbooks has_many :musicians, through: :songbooks end class musician < ApplicationRecord has_many :songbooks has_many :instruments, through: :songbooks end
And that's how you create a has_many :through association.
Which one should I use?
My rule of thumb is the following: If I need validations or any form of custom behavior in the relationship, I go with has_many :through. Otherwise (most cases) I go with has_and_belongs_to_many.
Thank you for reading!
What to do next
- Share this article with friends and colleagues. Thank you for helping me reach people who might find this information useful.
- You can check the official Rails documentation for associations here.
- If you want to learn more about Rails you can check RoR Tutorial. This and other very helpful books can be found in the recommended reading list.
- Send me an email with questions, comments or suggestions (it's in the About Me page)