验证多列的唯一性

问题描述 投票:0回答:3

是否有一种铁路方式来验证实际记录是唯一的而不仅仅是一列?例如,友谊模型/表不应具有多个相同的记录,例如:

user_id: 10 | friend_id: 20
user_id: 10 | friend_id: 20
ruby-on-rails ruby-on-rails-3 validation activerecord rails-activerecord
3个回答
323
投票

您可以按如下方式确定

validates_uniqueness_of
调用的范围。

validates_uniqueness_of :user_id, :scope => :friend_id

158
投票

您可以使用

validates
按一列验证
uniqueness

validates :user_id, uniqueness: {scope: :friend_id}

多列验证的语法类似,但您应该提供一个字段数组:

validates :attr, uniqueness: {scope: [:attr1, ... , :attrn]}

然而,上面所示的验证方法存在竞争条件,无法确保一致性。考虑以下示例:

  1. 数据库表记录应该由 n 字段唯一;

  2. 多个(两个或更多)并发请求,每个请求由单独的进程处理(应用程序服务器、后台工作服务器或任何正在使用的服务器),访问数据库以在表中插入相同的记录;

  3. 每个进程并行验证是否存在具有相同 n 字段的记录;

  4. 每个请求的验证都成功通过,每个进程都会在表中创建一条具有相同数据的记录。

为了避免这种行为,应该向数据库表添加一个“唯一约束”。您可以通过运行以下迁移,使用 add_index

 帮助器为一个(或多个)字段设置它:
class AddUniqueConstraints < ActiveRecord::Migration def change add_index :table_name, [:field1, ... , :fieldn], unique: true end end

警告

:即使设置了唯一约束,两个或多个并发请求也会尝试将相同的数据写入数据库,但这不会创建重复的记录,而是会引发 ActiveRecord::RecordNotUnique

 异常,您可以在应单独处理:
begin # writing to database rescue ActiveRecord::RecordNotUnique => e # handling the case when record already exists end



3
投票

add_index :friendships, [:user_id, :friend_id], unique: true

您可以使用 Rails 验证器,但一般来说我建议使用数据库约束。

更多阅读:

https://thoughtbot.com/blog/validation-database-constraint-or-both

© www.soinside.com 2019 - 2024. All rights reserved.