Ruby-on-rails 验证多列的唯一性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4870961/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Validate uniqueness of multiple columns
提问by re5et
Is there a rails-way way to validate that an actual record is unique and not just a column? For example, a friendship model / table should not be able to have multiple identical records like:
是否有一种铁路方式来验证实际记录是唯一的,而不仅仅是一列?例如,一个友谊模型/表不应该有多个相同的记录,例如:
user_id: 10 | friend_id: 20
user_id: 10 | friend_id: 20
回答by Dylan Markow
You can scope a validates_uniqueness_ofcall as follows.
您可以validates_uniqueness_of按如下方式确定调用范围。
validates_uniqueness_of :user_id, :scope => :friend_id
回答by potashin
You can use validatesto validate uniquenesson one column:
您可以使用对一列validates进行验证uniqueness:
validates :user_id, uniqueness: {scope: :friend_id}
The syntax for the validation on multiple columns is similar, but you should provide an array of fields instead:
多列验证的语法类似,但您应该提供一个字段数组:
validates :attr, uniqueness: {scope: [:attr1, ... , :attrn]}
However, validation approaches shown above have a race condition and can't ensure consistency. Consider the following example:
但是,上面显示的验证方法存在竞争条件,无法确保一致性。考虑以下示例:
database table records are supposed to be unique by nfields;
multiple (two or more) concurrent requests, handled by separate processes each (application servers, background worker servers or whatever you are using), access database to insert the same record in table;
each process in parallel validates if there is a record with the same nfields;
validation for each request is passed successfully, and each process creates a record in the table with the same data.
数据库表记录应该是唯一的n 个字段;
多个(两个或更多)并发请求,由单独的进程处理(应用程序服务器,后台工作服务器或您正在使用的任何程序),访问数据库以在表中插入相同的记录;
每个进程并行验证是否存在具有相同n 个字段的记录;
每个请求的验证都成功通过,每个进程在表中创建一个具有相同数据的记录。
To avoid this kind of behaviour, one should add a unique constraintto db table. You can set it with add_indexhelper for one (or multiple) field(s) by running the following migration:
为了避免这种行为,应该向 db 表添加一个唯一约束。您可以add_index通过运行以下迁移,使用helper 为一个(或多个)字段设置它:
class AddUniqueConstraints < ActiveRecord::Migration
def change
add_index :table_name, [:field1, ... , :fieldn], unique: true
end
end
Caveat: even after you've set a unique constraint, two or more concurrent requests will try to write the same data to db, but instead of creating duplicate records, this will raise an ActiveRecord::RecordNotUniqueexception, which you should handle separately:
警告:即使您设置了唯一约束,两个或多个并发请求也会尝试将相同的数据写入数据库,但这不会创建重复记录,而是会引发ActiveRecord::RecordNotUnique异常,您应该单独处理:
begin
# writing to database
rescue ActiveRecord::RecordNotUnique => e
# handling the case when record already exists
end
回答by Tate Thurston
This can be done with a database constraint on the two columns:
这可以通过对两列的数据库约束来完成:
add_index :friendships, [:user_id, :friend_id], unique: true
add_index :friendships, [:user_id, :friend_id], unique: true
You could use a rails validator, but in general I recommend using a database constraint.
您可以使用 rails 验证器,但通常我建议使用数据库约束。
More reading: https://robots.thoughtbot.com/validation-database-constraint-or-both
更多阅读:https: //robots.thoughtbot.com/validation-database-constraint-or-both

