Rails关联:关于Rails关联你需要知道的一切
关联是两个Active Record 模型之间的连接。它使在代码中对记录执行各种操作变得更加容易。我将关联分为四类:
- 一对一
- 一对多
- 多对多
- 多态一对多
如果您是 Ruby on Rails 的新手,请务必准备好您的Rails 项目,并查看如何在 Rails 中创建模型。
一对一
设置一对一关系时,意味着一条记录包含另一个模型的唯一实例。例如,如果应用程序中的每个用户只有一个个人资料,则可以将模型描述为:
class User < ApplicationRecord class Profile < ApplicationRecord
has_one :profile belongs_to :user
end end
给定关系中的一个模型将具有has_one方法调用,而另一个模型将具有belongs_to。它用于描述哪个模型包含对另一个模型的外键引用,在你的例子中,是 profiles 模型。
使用RSpec 测试覆盖你的关联代码,以确保一切按预期运行。
一对多
一对多关联是最常用的关系类型。这种关联表示模型 A 的每个实例可以有零个或多个模型 B 的实例,而模型 B 只能属于一个模型 A。
我们通过一个例子来说明。假设你想创建一个用户可以编写多个故事的应用程序,你的模型应该如下所示:
class User < ApplicationRecord class Story < ApplicationRecord
has_many :stories belongs_to :user
end end
在这里,决定哪个模型拥有has_many哪个模型比一对一belongs_to关系更为重要,因为它会改变应用程序的逻辑。在这两种情况下,第二个模型都以外键的形式包含对第一个模型的引用。
第二个模型不知道第一个模型与它的关系——它不知道第一个模型是引用了多个模型还是只引用了一个模型。
创建的关系越多,关联测试就越复杂。建议您了解如何创建自己的关联工厂,以简化测试工作。
多对多
多对多关系比较复杂,可以用两种方式处理:“拥有并属于多个”和“通过多个”关系。
拥有并属于许多人
关联模型与另一个模型has_and_belongs_to_many建立直接的多对多连接。它比另一种方法更简单,因为它只需要has_and_belongs_to_many两个模型都调用即可。
例如:假设一个用户可以拥有多个不同的角色,而同一个角色又可以包含多个用户,那么你的模型可能如下所示:
class User < ApplicationRecord class Role < ApplicationRecord
has_and_belongs_to_many :roles has_and_belongs_to_many :users
end end
要使此关联生效,您需要创建一个连接表。该表连接两个不同的模型。连接表是create_join_table :user, :role在单独的迁移文件中使用 Rails 函数创建的。
class CreateUserRoles < ActiveRecord::Migration
def change
create_table :user_roles, id: false do |t|
t.references :user, index: true, foreign_key: true
t.references :role, index: true, foreign_key: true
end
end
end
这是一个非常简单的方法,但是你无法直接访问相关对象,你只能持有对两个模型的引用,而不能持有其他任何引用。
许多通过
定义多对多关系的另一种方法是使用“通过多对多”关联类型。这里需要定义一个单独的模型来处理两个不同模型之间的连接。
与其再举新的例子,不如看看这个例子!它解释了关于这种关联的所有你需要知道的内容。
以关联关系为例has_and_belongs_to_many,这次三个模型应该这样写:
class User < ApplicationRecord
has_many :user_roles
has_many :roles, through: :user_roles
end
class UserRoles < ApplicationRecord
belongs_to :user
belongs_to :role
end
class Role < ApplicationRecord
has_many :user_roles
has_many :users, through: :user_roles
end
通过这种关联,您可以执行user.role诸如获取所有已连接的第二个模型实例列表之类的操作。它还可以让您访问与第一个模型和第二个模型之间的关系相关的特定数据。
多态性
多态关联是目前最先进的关联类型。当一个模型可能属于多个不同的模型时,可以使用多态关联。
假设您希望能够为用户和故事添加评论功能。您希望这两个模型都支持评论。以下是声明方式:
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
end
class Employee < ApplicationRecord
has_many :comment, as: :commentable
end
class Product < ApplicationRecord
has_many :comment, as: :commentable
end
你可以把多态belongs_to声明理解为设置一个任何其他模型都可以使用的接口。要声明多态接口,你需要在模型中同时声明一个外键列和一个类型列。完成后,你应该运行迁移。
class CreateComments < ActiveRecord::Migration
def change
create_table :comments do |t|
t.text :body
t.integer :commentable_id
t.string :commentable_type
t.timestamps
end
add_index :comments, :commentable_id
end
end
使用引用可以简化此迁移过程:
class CreateComments < ActiveRecord::Migration
def change
create_table :comments do |t|
t.text :body
t.references :commentable, polymorphic: true, index: true
t.timestamps
end
end
end
其他选项
在定义模型之间的关系时,还有一些其他选项可以使用,我将介绍其中最常用的两种。
类名
如果无法从关联名称推导出另一个模型的名称,您可以使用该
:class_name选项来提供模型名称。您可以在RailsGuides上阅读更多相关信息。
例如:您希望 belongs_to 关系调用作者,但存在两个问题:
- 没有名为“此”的型号。
- 故事表缺少一个
author_id字段。
解决方法很简单!要让它生效并防止测试失败,你只需要指定:foreign_key类的实际名称即可:
class Story < ApplicationRecord
belongs_to :author, class_name: 'User', foreign_key: 'user_id'
end
依赖
当您想要清除孤立记录时,可以使用此选项,因为孤立记录可能会导致各种问题。当您删除或销毁与模型 B 关联的模型 A,但模型 B 本身并未被删除时,就会产生孤立记录。
class User < ApplicationRecord
has_many :stories, dependent: :destroy
end
例如:假设用户 Maria 写了很多故事。然后,你从数据库中删除了 Maria,但这些故事的 user_id 列仍然设置为 Maria 的 ID。这些故事被称为孤立记录。
感谢阅读!
本文最初发表于Kolosek Blog。
文章来源:https://dev.to/neshaz/everything-there-is-to-know-about-associations-in-rails-52ii




