Associations
Real apps are made of related data: authors and books, posts and comments, doctors and patients. Rails associations let you describe those relationships once and get a rich set of helper methods for free.
Learn Associations in our free Ruby course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Ruby course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
By the end of this lesson you'll wire up has_many, belongs_to, has_many :through, and has_and_belongs_to_many, and understand foreign keys and dependent: :destroy.
What You'll Learn in This Lesson
1️⃣ One-to-Many: has_many and belongs_to
The most common association is one-to-many. The "one" side declares has_many ; the "many" side declares belongs_to and holds the foreign key column ( author_id ). Add dependent: :destroy so children don't outlive their parent.
2️⃣ Many-to-Many: :through and HABTM
When records relate on both sides, use a many-to-many . Prefer has_many :through when the join needs its own data; reach for has_and_belongs_to_many only for a plain link with nothing extra to store.
Your turn. Complete a blog's Post and Comment models so the one-to-many works end to end.
Mini-Challenge: A Tagging System
Model tags with has_many :through : a Post and a Tag joined by a Tagging . Write all three model classes.
Common Errors (and the fix)
- Missing foreign key — belongs_to needs a _id column; add it with t.references :author in a migration.
- Putting belongs_to on the wrong model — It goes on the table that holds the foreign key, not the one with has_many.
- Orphaned children after delete — Without dependent: :destroy , deleting a parent can leave dangling rows.
- Reaching for HABTM too soon — If the join ever needs its own data, you'll want has_many :through instead.
- Pluralisation typos — has_many takes a plural symbol ( :books ), belongs_to a singular one ( :author ).
Pro Tips
- 💡 belongs_to is required by default: since Rails 5, the parent must be present unless you say optional: true .
- 💡 Use inverse_of: it lets the two ends share one in-memory object and avoids extra queries.
- 💡 Index your foreign keys: t.references adds an index automatically, which keeps lookups fast.
📋 Quick Reference — Associations
Relationship
Declaration
One-to-many (one side)
has_many :books
One-to-many (many side)
belongs_to :author
Delete children too
dependent: :destroy
Many-to-many (join model)
has_many :tags, through: :taggings
Many-to-many (no model)
has_and_belongs_to_many :books
Foreign key (migration)
t.references :author
Frequently Asked Questions
🎉 Lesson Complete!
- ✅ has_many / belongs_to model one-to-many relationships
- ✅ The foreign key ( author_id ) lives on the belongs_to side
- ✅ dependent: :destroy removes children with their parent
- ✅ has_many :through joins with an explicit model that can carry data
- ✅ has_and_belongs_to_many is the no-model many-to-many
- ✅ Next lesson: Validations & Callbacks — keeping data clean
Practice quiz
Which association declares that one Author has many Books?
- belongs_to :books
- has_many :books
- has_one :books
- habtm :books
Answer: has_many :books. has_many :books goes in the Author model to express the one-to-many side.
On which model does the foreign key column normally live?
- The model that declares has_many
- Neither model — it is in a join file
- The model that declares belongs_to
- Always the Author model
Answer: The model that declares belongs_to. The belongs_to side holds the foreign key, e.g. books.author_id.
Following Rails conventions, what is the foreign key column for Book belongs_to :author?
- books_author
- author_key
- id_author
- author_id
Answer: author_id. Rails expects a column named author_id by convention.
What does dependent: :destroy do on has_many?
- Prevents deleting the parent
- Deletes associated child records when the parent is destroyed
- Marks children as archived
- Renames the foreign key
Answer: Deletes associated child records when the parent is destroyed. dependent: :destroy removes the children (running their callbacks) when the parent is destroyed.
Which association is used for a many-to-many relationship WITH a join model you can add attributes to?
- has_one
- belongs_to
- has_many :through
- has_and_belongs_to_many
Answer: has_many :through. has_many :through uses an explicit join model, so the join can carry its own columns.
has_and_belongs_to_many (HABTM) requires what in the database?
- A join table with no model
- A single foreign key
- Two separate tables only
- A polymorphic column
Answer: A join table with no model. HABTM uses a join table (e.g. authors_books) with no dedicated model class.
For a Comment that belongs to a Post, what does post.comments return?
- A single Comment
- An ActiveRecord relation of that post's comments
- The post's id
- nil unless cached
Answer: An ActiveRecord relation of that post's comments. has_many gives a collection (relation) of the associated records.
Which line belongs in the Book model for a one-to-many with Author?
- has_many :author
- has_one :author_id
- references :author
- belongs_to :author
Answer: belongs_to :author. The child (Book) declares belongs_to :author.
In a has_many :through, what must the through model itself declare?
- Only validations
- has_many to both sides
- Nothing special
- belongs_to to BOTH joined models
Answer: belongs_to to BOTH joined models. The join model uses belongs_to to each of the two models it connects.
What does inverse_of help Rails do?
- Reverse a migration
- Recognise the two sides of an association point at the same in-memory object
- Delete records faster
- Validate uniqueness
Answer: Recognise the two sides of an association point at the same in-memory object. inverse_of tells Rails the two association ends are the same object, avoiding redundant queries.
Continue this course
- Previous: ActiveRecord Models & Migrations
- Next: Validations & Callbacks