One association, several possible types
Every association so far pointed at one kind of model
ActiveRecord associations: has_one/through covered belongs_to, has_many, has_one and :through, and each of them pointed at one other kind of model. Catalog::Lesson belongs_to :course always means a Catalog::Course on the other end. That fixed type is built into course_id: an integer column that only ever means a row in the courses table.
A comment that needs two homes
Picture a Comment model that has to attach to either an Article or a Photo: one comment thread under a blog post, another under an image. The previous course suggests two ordinary belongs_to lines:
class Comment < ApplicationRecord
belongs_to :article, optional: true
belongs_to :photo, optional: true
end
This works, but it has cracks. Nothing stops one comment row from having both article_id and photo_id set, or neither. Every new commentable type, say a course review or a lesson note, means another nullable column on the same table. And both lines need optional: true, because Rails 8 requires a belongs_to by default (lesson 1 of the previous course), and that requirement doesn't fit here.
The question this course answers
What if one association could point at either kind of model, decided per row, with no extra column for each new type? That's what a polymorphic association does, and it's the subject of this course: one association, several possible types, resolved at runtime instead of fixed by a single target column.
What's ahead
Lesson 2 introduces the two columns a polymorphic belongs_to needs and what each one stores. Lesson 3 covers the reverse side, has_many ..., as: :commentable, on each possible type. Lesson 4 covers dependent: :destroy and a trap worth knowing. Lesson 5 shows the same mechanism inside this app's own code, where it has been running unnoticed. Lesson 6 covers querying by type, and lesson 7 ties it together.
Key takeaways
- Every association in ActiveRecord associations: has_one/through pointed at one fixed kind of model. This course covers one association that has to point at several kinds.
- The naive fix, one nullable
belongs_tocolumn per type, allows invalid combinations (both set, or neither) and needs a new column for every new type. - A polymorphic association solves this with one association resolved per row instead of one column per type.
- The seven lessons go from the two required columns, through the reverse side and
dependent:, to an example already in this app and querying by type.
Keep going with lesson 2
The two columns a polymorphic belongs_to needs
Explains the commentable_type and commentable_id columns and how reading commentable returns the original row.
A free account also gives you the quizzes, your progress and notes, and the discussion.