0Pricing
Ruby Academy · 课时

关联

has_many 与 belongs_to

关联 是 CoddyKit 上的免费 Ruby Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Ruby Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Ruby Academy 课程共包含 4 节课。

什么是关联

关联用于声明模型之间的关系,让 Active Record 可以为您访问相关的行。您无需编写连接 SQL,而是调用类似 user.posts 的方法。

  • 关联反映了数据库中的外键。
  • 关联会自动生成辅助方法。
  • 关联让代码读起来更符合业务领域。

belongs_to

belongs_to 表示当前模型持有一个指向另一个模型的外键。属于 Post 的 Comment 会有一个 post_id 列。

class Comment < ApplicationRecord
  belongs_to :post
end

# comment.post returns the parent Post
# Requires a post_id column on comments

has_many

has_many 表示另一侧的关系:一条记录拥有多个其他记录。一个 Post 拥有多条 Comment 记录。外键位于多的一侧。

class Post < ApplicationRecord
  has_many :comments
end

# post.comments returns all related comments
# post.comments.create(body: "Nice!")

外键位于哪里

使用 belongs_to 的模型持有外键。对于 Post 和 Comment,comments 表包含 post_id。请在迁移中使用 t.references :post 或 add_reference 完成设置。

create_table :comments do |t|
  t.references :post, foreign_key: true
  t.text :body
  t.timestamps
end

生成的方法

has_many :comments 会为您提供一个包含实用方法的集合:

  • 使用 post.comments 读取。
  • 使用 post.comments.create(...) 添加关联记录。
  • 使用 post.comments.count 计数。
  • 使用 post.comment_ids 获取这些记录的 id。
post = Post.find(1)
post.comments.create(body: "First!")
puts post.comments.count

has_one

has_one 表示一对一连接,例如一个拥有一个 Profile 的 User。外键仍然位于另一个模型中(profiles.user_id)。

class User < ApplicationRecord
  has_one :profile
end

class Profile < ApplicationRecord
  belongs_to :user
end

通过 through 实现多对多

对于多对多关系,请使用连接模型和 has_many through。一个 Student 通过 Enrollment 记录拥有多条 Course 记录。

class Student < ApplicationRecord
  has_many :enrollments
  has_many :courses, through: :enrollments
end

class Enrollment < ApplicationRecord
  belongs_to :student
  belongs_to :course
end

依赖选项

使用 dependent 决定删除父记录时子记录会发生什么:

  • dependent: :destroy 也会删除子记录。
  • dependent: :nullify 会清除子记录的外键。
  • dependent: :restrict_with_error 会阻止删除。
class Post < ApplicationRecord
  has_many :comments, dependent: :destroy
end

N+1 查询问题

遍历记录并访问关联时,可能会为每条记录执行一次查询,这就是令人头疼的 N+1 问题。加载 10 篇文章及其评论时,可能会执行 11 次查询,而不是 2 次。

随着数据增长,这会让应用程序在不易察觉的情况下变慢。

# N+1: one query per post for comments
Post.all.each do |post|
  puts post.comments.count
end

使用 includes 修复 N+1

includes 会告诉 Active Record 使用几次查询预先加载关联,而不是执行大量查询。这是解决 N+1 问题的标准方法。

Post.includes(:comments).each do |post|
  puts post.comments.count
end

使用 class_name 自定义名称

当关联名称与模型名称不匹配时,请使用 class_name 和 foreign_key 等选项。例如,可以定义一个由 User 模型支持的 author 关联。

class Post < ApplicationRecord
  belongs_to :author, class_name: "User"
end

快速检查

测试您对关联的理解。

回顾:关联

您学习了如何建立模型之间的关系:

  • belongs_to 持有外键;has_many 和 has_one 位于关系的另一侧。
  • has_many through 用于实现多对多关系。
  • dependent 控制级联删除。
  • 使用 includes 避免 N+1 查询。

接下来,我们将使用验证确保数据完整性,并学习如何查询。

常见问题解答

「关联」课时是免费的吗?

是的 — 「关联」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Ruby Academy 课程的其余内容,请升级到 CoddyKit PRO。 Ruby Academy 课程共包含 4 节课。

「关联」这节课中我会学到什么?

has_many 与 belongs_to 你通过在浏览器中直接运行的动手代码来练习 Ruby Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Ruby Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Ruby Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「关联」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Ruby Academy 课中编写并运行代码吗?

能。每节 Ruby Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. Active Record 基础
  2. 迁移
  3. 关联
  4. 验证与查询
← 返回 Ruby Academy