Rails 中的自引用关联:原理与实现
在 Rails 中,模型通常通过关联与其他模型建立联系,例如 User has_many :posts 和 Post belongs_to :user。这种模式涉及两个不同的模型和数据表。
但有时一个模型需要与自身建立关系——即同张表中的记录相互引用。这就是所谓的自引用关联。
一个典型例子是员工与主管的关系:主管本身也是员工,因此所有数据都存储在同一张 employees 表中。
首先生成模型:
rails new self_referential --api
cd self_referential
rails generate model Employee name:string manager_id:integer
rails db:migrate
关键字段是 manager_id,它指向同一张表中的另一条记录。
此时直接调用 employee.manager 会报错,因为 Rails 尚未知道如何解析这个关联。我们需要在模型中显式声明:
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
这里使用 class_name 告诉 Rails 关联的目标仍是 Employee 模型(而非不存在的 Manager),并通过 foreign_key 指定使用 manager_id 字段作为外键。
现在可以顺畅地使用双向关系:
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
这种模式广泛适用于多种场景:评论的父子结构(通过 parent_id)、用户互相关注、分类的嵌套子类等。本质上都是通过一个指向自身表的外键字段,并辅以正确的模型配置来实现。