资料来源:Rails Guide
Guide:
-在模型之间构建关联
-理解不同种类的关联
-使用关联提供的方法
1. Definition:
What? 是模型之间的连接方式
Why? 增强可读性,使得常用的操作变得简单
2. Types:
2.1. Various Types of Associations
belongs_to
, has_one
, has_many
has_one :through
, has_many :through
高级: 单表继承,多态关联,自关联
2.2. Different Choices between Associations
-(1) 选择belongs_to
vs has_one
: 通过模型数据之间实际的意义来判断
-(2) 选择has_many :through
vs has_and_belongs_to_many
: 使用前者具有可扩展性
2.3. Advanced Associations:
2.3.1 Polymorphic
多态关联和面向对象的多态不同,它表示一个模型可以通过一个关联属于多个其他模型。可以把多态关联简单的想象成为一个"接口",供任何其他模型使用。注意:需要在数据库层添加外键列和它对应的类型,通过它们可以知道关联的是哪个模型的哪行记录。
t.references :imageable, polymorphic: true, index: true
belongs_to :imageable, polymorphic: true
has_many :pictures, as: :imageable
2.3.2 STI
单表继承和面向对象的继承类似,可共享属性和父类的方法,在同一张表中。可以简单的把它理解为在模型层实现继承,并在数据库层实现操作存储在一张表的机制。注意:需要手动在数据库层添加type
字段。除此之外,单表继承还可以给子类定义他所特有的行为,当然在这里可以用到面向对象的多态机制,在父类中定义抽象方法,在子类中具体实现,不知道对象类型的情况下直接调用相同名称的方法得到不同实现。
rails g model sub --parent=super
2.3.3 Self Join
自连接是一个模型通过外键连接自己本身。例如:员工之间的关系,有领导和被领导的关系,但本质上他们都是公司雇佣的劳动力,所以可以使用自关联减少添加其他表。
t.references :manager, index: true
belongs_to :manager, class_name: 'Employee'
has_many: subordinates, class_name: 'Employee', foreign_key: 'manager_id'
3. Tips:
-(1) 控制缓存 关联查询会自动存入缓存中,使用reload
可以更新缓存。
-(2) 避免命名冲突 不要使用自带的实例方法名作为关联名称,如attributes
。
-(3) 更新模式 保证关联的模式与之相匹配,明确数据库层外键是哪一列。
-(4) 控制关联域 当关联的模型属于某个模块时,要是用class_name
指定模块名加类名。
4. Gift Methods with Associations:
4.1 belongs_to, has_one
-(1) 赠送的方法:build_association, create_association, create_association!
-(2) 选项:autosave, class_name, dependent, foreign_key, primary_key, validate
---赠送方法之:belongs_to
:counter_cache, inverse_of, polymorphic, touch, optional
---赠送方法之:has_one
:as, source, source_type, through
-(3) 域: where, includes, readonly, select
4.2 has_many
-(1) 赠送的方法:collection <<, delete, destroy, clear, empty?
size, find, where, exists?, build, create, create!
(collection_singular)_ids, (collection_singular_ids)=(ids)
-(2) 选项:through, class_name, foreign_key, source, dependent
as, autosave, counter_cache, primary_key, inverse_of, source_type, validate
-(3) 域: where, group, includes, limit, offset, order, readonly, select, distinct
Tips: 确保多对多关系中间表的记录在数据库层的唯一性
add_index :readings, [:person_id, :article_id], unique: true
5. Association Callbacks
Triggered by events in the life cycle of a collection.
before_add, after_add, before_remove, after_remove: [:check_sth, :calculate_sth]
private def check_method ... end def calculate_method ... end
如果before_add
回调抛出异常,对象不会被添加到关联记录中;
如果before_remove
回调抛出异常,对象不会从该关联记录中删除。
6. Association Extension
Add extension methods to associations.
铁轨并没有限制你只能使用它提供的关联方法,你也可以使用自定义的关联方法。这就十分有趣了,你可以通过扩展对象的匿名模块,添加新的查询方法,创建等其他方法。
-(1) 直接在匿名代码块中添加新的关联方发,只属于这个关联
-(2) 使用实名的扩展模块,可在多个关联中共享自定义的关联方法
扩展可以引用内部的关联代理owner, reflection, target