belongs_to: the side that holds the foreign key

Free preview 3 min to read

A line from this app's code

module Catalog
  class Lesson < ApplicationRecord
    belongs_to :course, class_name: "Catalog::Course", touch: true
  end
end

This is from app/models/catalog/lesson.rb, word for word. Every lesson this app shows you belongs to one course, and this line is what makes lesson.course return that course instead of raising NoMethodError. The touch: true option updates the course's updated_at whenever the lesson is saved.

Querying was covered, declaring wasn't

The last lesson of SQL: JOIN fundamentals, "JOINs in Rails: ActiveRecord associations", covered joins, includes, eager_load, preload and the N+1 problem in depth, with lines like Catalog::Course.joins(:lessons). It never explained how :lessons or :course came to exist as names you can pass to joins(...). This course fills that gap. It shows how belongs_to, has_many and has_one are written, and ends with the two :through variants in its title.

What belongs_to declares

belongs_to :course means this table, lessons, holds a foreign key column that points at another table, courses. The schema shows it:

lessons table:
  course_id  bigint   <- the foreign key
  title      jsonb
  position   integer

course_id is a plain column holding a courses.id value. belongs_to :course turns that integer into lesson.course, a Catalog::Course instance, loaded with its own query the first time you ask for it.

Required by default

Rails.application.config.active_record.belongs_to_required_by_default
# => true

This is this app's own config. In Rails 8, a plain belongs_to :course makes course required. Saving a lesson without a course_id fails validation before anything reaches the database, the same instinct behind save! raising on bad data instead of writing a broken row. A scratch table with the same shape showed it: a lesson without a course failed with Validation failed: Scratch course must exist, not with a database error.

Where the course goes

This lesson covered the job of belongs_to: saying which side holds the foreign key. Lesson 2 covers the other side, has_many. Lesson 3 covers has_one, the single-record version of the same idea. Lesson 4 covers the options for when the defaults don't fit: foreign_key, class_name and optional. Lessons 5 and 6 reach the subject in the title, has_many :through and has_one :through, two ways to reach a third model across a middle one. Lesson 7 ties them together.

Key takeaways

  • belongs_to :course, copied from this app's Catalog::Lesson, means this table holds the foreign key column, course_id, pointing at another table.
  • This app's config confirms that Rails 8 makes a plain belongs_to required by default, and a scratch table without a course failed validation as expected.
  • This course teaches declaring associations. Querying them with joins, includes and the rest is covered in the lesson "JOINs in Rails: ActiveRecord associations" of SQL: JOIN fundamentals.
Lesson 1 of 7 · free

Keep going with lesson 2

has_many: the side with the collection

How has_many returns a Relation of child rows, with dependent: :destroy and build filling the foreign key.

A free account also gives you the quizzes, your progress and notes, and the discussion.

Type to start searching...