Tbh I had no idea this was even a thing until recently. I've been working with Rails for a while now and somehow never came across it.
So let me explain it the way I understood it.
You know how we normally do associations in Rails, User has many Posts, Post belongs to User. Two different models, two different tables. Simple.
But what if a model needs to reference itself? Like same table, same model, but pointing to another record in the same table?
That's all a self referential association is.
The example that made it click for me was Employee and Manager. A manager is just another employee right? So both live in the same employees table.
Let's build it:
rails new self_referential --api
cd self_referential
rails g model Employee name:string manager_id:integer
rails db:migrate
The key column here is manager_id — it just points back to the same table.
Now if you go to Rails console and try alice.manager, you'll get a NoMethodError. Makes sense, we haven't told Rails anything yet.
Here's where you add this to the model:
class Employee < ApplicationRecord
belongs_to :manager, class_name: "Employee",
foreign_key: :manager_id,
optional: true
has_many :subordinates, class_name: "Employee",
foreign_key: :manager_id
end
The reason we need class_name and foreign_key, Rails tries to guess the table from the association name. belongs_to :manager makes Rails look for a managers table. That doesn't exist. So we just tell it explicitly, look in employees table, use manager_id column. That's it.
Now this works:
john = Employee.create!(name: "John")
alice = Employee.create!(name: "Alice", manager: john)
bob = Employee.create!(name: "Bob", manager: john)
carol = Employee.create!(name: "Carol", manager: alice)
alice.manager.name # => "John"
john.subordinates.map(&:name) # => ["Alice", "Bob"]
carol.manager.name # => "Alice"
john.manager # => nil
One table, one model, navigate relationships in any direction.
Once you get this pattern you'll start seeing it everywhere, comment replies with parent_id, users following other users, categories with subcategories. Same idea every time.
honestly, it sounds scarier than it is. Just a column pointing back to the same table with a bit of guidance for Rails.
Top comments (0)