关联
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 commentshas_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.counthas_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
endN+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 反馈 — 无需本地设置。