跳过正文

第6篇:ActiveRecord 关联关系

·347 字·2 分钟
xieweicong
作者
xieweicong

学习目标:掌握 ActiveRecord 关联的实现原理和最佳实践

引言
#

关联(Associations)是 ActiveRecord 最强大的特性之一,它让我们能够优雅地表达对象之间的关系。

1. 关联类型
#

1.1 belongs_to - 属于关系
#

class Post < ApplicationRecord
  belongs_to :user
end

# 生成的方法:
post.user          # 获取关联的user
post.user = user   # 设置关联
post.build_user    # 构建新user
post.create_user   # 创建并保存user
post.reload_user   # 重新加载

数据库结构

create_table :posts do |t|
  t.references :user, foreign_key: true
end

1.2 has_one - 一对一
#

class User < ApplicationRecord
  has_one :profile
end

# 生成方法与 belongs_to 类似
user.profile
user.profile = profile
user.build_profile
user.create_profile

1.3 has_many - 一对多
#

class User < ApplicationRecord
  has_many :posts
end

user.posts                  # 获取所有posts
user.posts << post          # 添加post
user.posts.build            # 构建新post
user.posts.create           # 创建并保存
user.posts.count            # 计数
user.posts.clear            # 清空
user.posts.destroy_all      # 删除所有

1.4 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

1.5 多态关联
#

class Comment < ApplicationRecord
  belongs_to :commentable, polymorphic: true
end

class Post < ApplicationRecord
  has_many :comments, as: :commentable
end

class Photo < ApplicationRecord
  has_many :comments, as: :commentable
end

# 数据库结构
create_table :comments do |t|
  t.references :commentable, polymorphic: true
end

2. 关联选项
#

2.1 常用选项
#

class User < ApplicationRecord
  has_many :posts,
    dependent: :destroy,      # 删除策略
    foreign_key: 'author_id', # 外键名
    class_name: 'Article',    # 关联类名
    inverse_of: :author,      # 反向关联
    counter_cache: true,      # 计数缓存
    touch: true              # 更新时间戳
end

2.2 dependent 选项
#

has_many :posts, dependent: :destroy      # 删除关联记录
has_many :posts, dependent: :delete_all   # 直接删除(不触发回调)
has_many :posts, dependent: :nullify      # 设置外键为NULL
has_many :posts, dependent: :restrict_with_error  # 有关联时阻止删除

3. 预加载策略
#

3.1 三种预加载方式
#

# includes - 智能选择
Post.includes(:user)

# preload - 分离查询
Post.preload(:user)

# eager_load - JOIN查询
Post.eager_load(:user)

3.2 嵌套预加载
#

Post.includes(user: [:profile, :company])
Post.includes(:user, comments: :author)

4. 实现原理
#

4.1 宏的实现
#

# activerecord/lib/active_record/associations.rb
module ClassMethods
  def belongs_to(name, scope = nil, **options)
    reflection = Builder::BelongsTo.build(self, name, scope, options)
    Reflection.add_reflection(self, name, reflection)
  end
end

4.2 Association 类
#

# activerecord/lib/active_record/associations/association.rb
class Association
  attr_reader :owner, :reflection

  def initialize(owner, reflection)
    @owner = owner
    @reflection = reflection
  end

  def load_target
    # 加载关联对象
  end
end

5. 本章总结
#

关联是 ActiveRecord 的核心特性,理解其实现原理对优化查询至关重要。


上一篇ActiveRecord 查询接口 下一篇ActiveModel 接口 返回学习指南首页