在Rails中设置时验证关联的模型是否存在

时间:2015-12-01 15:59:26

标签: ruby-on-rails validation activerecord

假设我们在Rails中有以下Post模型:

class Post < ActiveRecord::Base
  belongs_to :user
end

user不是必需的,但是当它被设置时,我们希望它是一个有效的关联(我们不希望有一个user_id的帖子不在数据库)。测试失败:

expect(Post.new).to be_valid
expect(Post.new(user_id: 0)).not_to be_valid
expect(Post.new(user: User.create)).to be_valid

一种解决方案是:

validates_presence_of :user, unless: "user_id.nil?"

这将执行所需的任务但不是很漂亮,因为我们不想为我们的应用程序中的每个belongs_to编写它。

有没有办法告诉rails检查相关模型是否存在?这不是我们想要的东西吗? (为什么我们想要一个不指向任何东西的association_id?)

1 个答案:

答案 0 :(得分:1)

为了保证关联在数据库级别有效,MySQL和PostgreSQL能够强制执行表上的外键列的有效性。 Since Rails 4.2,这些外键约束可以作为迁移的一部分创建。

您可以在迁移中至少以两种方式执行此操作。将foreign_key属性传递给add_reference

add_reference :posts, :user, index: true, foreign_key: true

或使用add_foreign_key跟随add_reference,这也为您提供了在删除用户时重置密钥的选项:

add_reference :posts, :user, index: true
add_foreign_key :posts, :user, on_delete: :nullify

通过将哈希传递给foreign_key的{​​{1}}属性来结合这两种方法(自Rails 4.2.1起):

add_reference

如果查询通过将add_reference :posts, :user, index: true, foreign_key: {on_delete: :nullify} 更新为指向不存在的用户来中断外键约束,则查询将失败并在Rails中引发异常。

正如您所提到的,您还可以创建验证,以便在创建user_id之前检查User是否存在。但是,这不会像数据库上的外键约束那样强大,因为在验证传递和创建Post之间可以删除User

为了帮助在应用程序级别保持引用有效,通常更好的做法是避免将用户ID直接传递给Post构造函数。相反,请尝试始终使用Post对象作为输入,例如通过调用User