Tutorial
Step 8: Polymorphic Relationships
Let’s introduce the concept of a Note. A Note can belong to a Department, an Employee, or a Team. For this, we’ll need to introduce the concept of polymorphism.
| id | notable_id | notable_type | body |
|---|---|---|---|
| 1 | 1 | Employee | A Sample Note! |
| 2 | 1 | Department | Another Sample Note! |
| 3 | 1 | Team | A Third Sample Note! |
The Rails Stuff 🚂
$ rails generate model Note notable:references{polymorphic}:index
$ bin/rails db:migrateMake sure to add the corresponding model relationships:
# app/models/employee.rb
has_many :notes, as: :notable
# app/models/team.rb
has_many :notes, as: :notable
# app/models/department.rb
has_many :notes, as: :notable
# app/models/note.rb
belongs_to :notable, polymorphic: trueFinally, make sure to edit your seed file - check out the diff to see the necessary adjustments.
The Graphiti Stuff 🎨
$ bin/rails g graphiti:resource Note body:textLet’s create our NoteResource:
class NoteResource < ApplicationResource
attribute :body, :string
filter :notable_id, :integer
filter :notable_type, :string, allow: %w(Employee Department Team)
polymorphic_belongs_to :notable do
group_by(:notable_type) do
on(:Employee)
on(:Team)
on(:Department)
end
end
endAnd corresponding associations:
# app/models/employee.rb
polymorphic_has_many :notes, as: :notable
# app/models/team.rb
polymorphic_has_many :notes, as: :notable
# app/models/department.rb
polymorphic_has_many :notes, as: :notableDigging Deeper 🧐
When defining a polymorphic relationship for our API, we’re saying “grab
all the parent records, group them by a type column, and execute
different queries for each type”. This way records with notable_type ==
'Employee' can hit the employees table, but records with
notable_type == 'Department' could in theory load from a different API
altogether.
Each of the on lines defines a new belongs_to association. That
means you can customize just like always:
on(:Team).belongs_to :team, resource: SomeCustomTeamResource do
# assign {}
# link {}
# ... etc ...
end