Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Models  ›  Lesson

Model Relationships (Associations)

Model Relationships 15 minbelongs_to sits on the model whose table holds the foreign key, has_many or has_one sits on the other side, and has_many :through connects two models via a join model.

Model Relationships (Associations)

A review is always about a book, and a book collects many reviews. You could look them up by hand with Review.where(book_id: book.id), but Rails lets you declare the relationship once and then say book.reviews. Getting the declaration right comes down to one question: which table holds the foreign key?

The rule

The table with the foreign key belongs_to; the other side has_many.

class Review < ApplicationRecord
  belongs_to :book          # reviews.book_id
  belongs_to :member        # reviews.member_id
end

class Book < ApplicationRecord
  has_many :reviews, dependent: :destroy
end

class Member < ApplicationRecord
  has_many :reviews
  has_many :reviewed_books, through: :reviews, source: :book
end

What each gives you:

  • belongs_to :book — review.book, review.book = some_book. Since Rails 5 the book is required: a review without one fails validation. Add optional: true to allow none.
  • has_many :reviews — book.reviews, book.reviews.create(rating: 5, member: m), book.reviews.count.
  • has_one — like has_many but for a single record, such as has_one :profile.
  • has_many :through — reach across a join model. Members and books are many-to-many, and the reviews table sits between them.
  • dependent: :destroy — destroying the book destroys its reviews first, so none are left orphaned.

The foreign key column comes from the migration: book:references creates book_id. Rails guesses names from the association: belongs_to :book looks for book_id and the Book class.

The shortcut

Draw the tables and find the _id column. The model whose table has it gets belongs_to. The model it points at gets has_many (or has_one). If two models point at each other through a third table, add has_many :through on each.

Placing the associations for reviewsStep 1 of 4
  1. Find the foreign keys

    The reviews table has book_id and member_id.

The trap is writing belongs_to on the side without the column, for example Book belongs_to :review. Rails would look for a review_id column on books that does not exist.

Drills

Answer fast — trust the rule.

quick drill

The reviews table has a book_id column. Which declaration goes in Review?

quick drill

A new review is saved with no book. What happens by default?

quick drill

Which association lets member.reviewed_books work?

quick drill

A book with 3 reviews is destroyed, and has_many :reviews, dependent: :destroy is set. What happens?

Remember

  • The table with the foreign key belongs_to; the other side has_many.
  • Shortcut: find the _id column; through for many-to-many.
  • Trap: belongs_to on the side without the column.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainWire up books, reviews and members

In Bookclub a book has many reviews, each review is written by one member, and members can see every book they have reviewed. Write the associations for Book, Review and Member, say which table holds which foreign key, and explain what dependent: :destroy does.