POSTS
Rails中建立AR模型的关联关系
Rails AR模型中支持的六种关联:
belongs_to (一对一,属于xx,在此模型添加xx外键)
has_one (一对一,拥有xx,在xx模型添加自身外键)
has_many (一对多,在xx模型添加自身外键)
has_many :through (多对多,有中间模型,中间表中有主键)
has_one :through (一对一,有中间模型)
has_and_belongs_to_many (多对多,无中间模型但需要建立中间表,中间表中无主键)
1.belongs_to:
class Book < ApplicationRecord
belongs_to :author
end
在 belongs_to 关联声明中必须使用单数形式。如果在上面的代码中使用复数形式定义 author 关联,应用会报错,提示“uninitialized constant Book::Authors”。这是因为 Rails 自动使用关联名推导类名。如果关联名错误地使用复数,推导出的类名也就变成了复数。
2.has_many:
class Author < ApplicationRecord
has_many :books
end
has_many 关联建立两个模型之间的一对多关系。在 belongs_to 关联的另一端经常会使用这个关联。has_many 关联表示模型的实例有零个或多个另一模型的实例。声明 has_many 关联时,另一个模型使用复数形式。
3.has_many :through
- has_many :through 关联经常用于建立两个模型之间的多对多关联。这种关联表示一个模型的实例可以借由第三个模型,拥有零个和多个另一模型的实例。例如,在医疗锻炼中,病人要和医生约定练习时间.
class Physician < ApplicationRecord
has_many :appointments
has_many :patients, through: :appointments
end
class Appointment < ApplicationRecord
belongs_to :physician
belongs_to :patient
end
class Patient < ApplicationRecord
has_many :appointments
has_many :physicians, through: :appointments
end
physician.patients = patients
会为新建立的关联对象创建联结模型实例。如果其中一个对象删除了,相应的联结记录也会删除。
- has_many :through 还能简化嵌套的 has_many 关联。例如,一个文档分为多个部分,每一部分又有多个段落,如果想使用简单的方式获取文档中的所有段落,可以这么做:
class Document < ApplicationRecord
has_many :sections
has_many :paragraphs, through: :sections
end
class Section < ApplicationRecord
belongs_to :document
has_many :paragraphs
end
class Paragraph < ApplicationRecord
belongs_to :section
end
获取当前文档的所有段落
@document.paragraphs
4.has_one :through
has_one :through 关联建立两个模型之间的一对一关系。这种关联表示一个模型通过第三个模型拥有另一模型的实例。例如,每个供应商只有一个账户,而且每个账户都有一个账户历史,那么可以这么定义模型:
class Supplier < ApplicationRecord
has_one :account
has_one :account_history, through: :account
end
class Account < ApplicationRecord
belongs_to :supplier
has_one :account_history
end
class AccountHistory < ApplicationRecord
belongs_to :account
end
5.has_and_belongs_to_many
has_and_belongs_to_many 关联直接建立两个模型之间的多对多关系,不借由第三个模型。例如,应用中有装配体和零件两个模型,每个装配体有多个零件,每个零件又可用于多个装配体,这时可以按照下面的方式定义模型:
class Assembly < ApplicationRecord
has_and_belongs_to_many :parts
end
class Part < ApplicationRecord
has_and_belongs_to_many :assemblies
end
6.自联结
设计数据模型时,模型有时要和自己建立关系。例如,在一个数据库表中保存所有雇员的信息,但要建立经理和下属之间的关系。这种情况可以使用自联结关联解决:
class Employee < ApplicationRecord
has_many :subordinates, class_name: "Employee",foreign_key: "manager_id"
belongs_to :manager, class_name: "Employee"
end
一样定义模型后,可以使用 @employee.subordinates 和 @employee.manager 检索了。
在迁移(模式)中,要添加一个引用字段,指向模型自身:
class CreateEmployees < ActiveRecord::Migration[5.0]
def change
create_table :employees do |t|
t.references :manager, index: true
t.timestamps
end
end
end
在 has_many :through 和 has_and_belongs_to_many 之间如何选择?
1.has_and_belongs_to_many,可以直接建立关联
2.使用 has_many :through,通过联结模型间接建立关联(中间表=联结模型)
根据经验,如果想把关联模型当做独立实体使用,要用 has_many :through 关联;如果不需要使用关联模型,建立 has_and_belongs_to_many 关联更简单(不过要记得在数据库中创建联结表)。
如果要对联结模型做数据验证、调用回调,或者使用其他属性,要使用 has_many :through 关联。