是否有一种轨道方式来验证实际记录是唯一的而不仅仅是一列?例如,友谊模型/表不应该具有多个相同的记录,例如:
user_id: 10 | friend_id: 20 user_id: 10 | friend_id: 20
您可以按如下方式调用 validates_uniqueness_of 调用范围 .
validates_uniqueness_of
validates_uniqueness_of :user_id, :scope => :friend_id
您可以使用validates在一列上验证 uniqueness :
uniqueness
validates :user_id, uniqueness: {scope: :friend_id}
多列验证的语法类似,但您应该提供一个字段数组:
validates :attr, uniqueness: {scope: [:attr1, ... , :attrn]}
但是,上面显示的验证方法具有竞争条件,无法确保一致性 . 请考虑以下示例:
数据库表记录应该是n个字段唯一的;
多个(两个或更多)并发请求,由每个单独的进程(应用程序服务器,后台工作服务器或您正在使用的任何服务器)处理,访问数据库以在表中插入相同的记录;
并行验证每个进程是否存在具有相同n个字段的记录;
每个请求的
要避免这种行为,应该为db表添加一个唯一约束 . 您可以通过运行以下迁移为一个(或多个)字段设置add_index helper:
class AddUniqueConstraints < ActiveRecord::Migration def change add_index :table_name, [:field1, ... , :fieldn], unique: true end end
警告:即使你设置了一个唯一的约束,两个或多个并发请求将尝试将相同的数据写入db,但不会创建重复的记录,这将引发一个ActiveRecord::RecordNotUnique异常,你应该单独处理:
begin # writing to database rescue ActiveRecord::RecordNotUnique => e # handling the case when record already exists end
您可能确实需要对db进行实际约束,因为验证会受到竞争条件的影响 .
当您持久保存用户实例时,Rails将通过运行SELECT查询来验证您的模型,以查看是否已存在所提供的user_id的任何用户记录 . 假设记录证明有效,Rails将运行INSERT语句以持久保存用户 . 如果您正在运行单个进程/线程Web服务器的单个实例,则此方法很有用 .
如果两个进程/线程试图在同一时间创建具有相同user_id的用户,则可能出现以下情况 .
在db上有唯一索引的情况下,上述情况将如下所示 .
从这篇博文中回答 - http://robots.thoughtbot.com/the-perils-of-uniqueness-validations
这可以通过两列上的数据库约束来完成:
add_index :friendships, [:user_id, :friend_id], unique: true
您可以使用rails验证器,但通常我建议使用数据库约束 .
更多阅读:https://robots.thoughtbot.com/validation-database-constraint-or-both
4 回答
您可以按如下方式调用
validates_uniqueness_of
调用范围 .您可以使用validates在一列上验证
uniqueness
:多列验证的语法类似,但您应该提供一个字段数组:
但是,上面显示的验证方法具有竞争条件,无法确保一致性 . 请考虑以下示例:
数据库表记录应该是n个字段唯一的;
多个(两个或更多)并发请求,由每个单独的进程(应用程序服务器,后台工作服务器或您正在使用的任何服务器)处理,访问数据库以在表中插入相同的记录;
并行验证每个进程是否存在具有相同n个字段的记录;
每个请求的
要避免这种行为,应该为db表添加一个唯一约束 . 您可以通过运行以下迁移为一个(或多个)字段设置add_index helper:
警告:即使你设置了一个唯一的约束,两个或多个并发请求将尝试将相同的数据写入db,但不会创建重复的记录,这将引发一个ActiveRecord::RecordNotUnique异常,你应该单独处理:
您可能确实需要对db进行实际约束,因为验证会受到竞争条件的影响 .
当您持久保存用户实例时,Rails将通过运行SELECT查询来验证您的模型,以查看是否已存在所提供的user_id的任何用户记录 . 假设记录证明有效,Rails将运行INSERT语句以持久保存用户 . 如果您正在运行单个进程/线程Web服务器的单个实例,则此方法很有用 .
如果两个进程/线程试图在同一时间创建具有相同user_id的用户,则可能出现以下情况 .
在db上有唯一索引的情况下,上述情况将如下所示 .
从这篇博文中回答 - http://robots.thoughtbot.com/the-perils-of-uniqueness-validations
这可以通过两列上的数据库约束来完成:
add_index :friendships, [:user_id, :friend_id], unique: true
您可以使用rails验证器,但通常我建议使用数据库约束 .
更多阅读:https://robots.thoughtbot.com/validation-database-constraint-or-both