Hi I wan't to validate the unique combination of 3 columns in my table.
Hi,我不验证表中3列的唯一组合。
Let's say I have a table called cars with the values :brand, :model_name and :fuel_type.
假设我有一个名为cars的表,值为:brand,:model_name和:fuel_type。
What I then want is to validate if a record is unique based on the combination of those 3. An example:
然后,我想要的是根据这3个记录的组合来验证一个记录是否惟一。一个例子:
brand model_name fuel_type
Audi A4 Gas
Audi A4 Diesel
Audi A6 Gas
Should all be valid. But another record with 'Audi, A6, Gas' should NOT be valid.
都应该是有效的。但“奥迪、A6、燃气”的另一项纪录不应成立。
I know of this validation, but I doubt that it actually does what I want.
我知道这种验证,但我怀疑它是否真的实现了我想要的。
validates_uniqueness_of :brand, :scope => {:model_name, :fuel_type}
5 个解决方案
#1
92
There is a syntax error in your code snippet. The correct validation is :
代码片段中有一个语法错误。正确的验证是:
validates_uniqueness_of :car_model_name, :scope => [:brand_id, :fuel_type_id]
or even shorter in ruby 1.9.x:
或者更短的ruby 1.9.x:
validates_uniqueness_of :car_model_name, scope: [:brand_id, :fuel_type_id]
with rails 4 you can use:
使用rails 4,您可以使用:
validates :car_model_name, uniqueness: { scope: [:brand_id, :fuel_type_id] }
with rails 5 you can use
使用rails 5可以使用
validates_uniqueness_of :car_model_name, scope: %i[brand_id fuel_type_id]
#2
11
Depends on your needs you could also to add a constraint (as a part of table creation migration or as a separate one) instead of model validation:
根据您的需要,您还可以添加约束(作为表创建迁移的一部分或作为单独的约束),而不是模型验证:
add_index :the_table_name, [:brand, :model_name, :fuel_type], :unique => true
Adding the unique constraint on the database level makes sense, in case multiple database connections are performing write operations at the same time.
如果多个数据库连接同时执行写操作,那么在数据库级别上添加惟一约束是有意义的。
#3
4
I would make it this way:
我会这么做:
validates_uniqueness_of :model_name, :scope => {:brand_id, :fuel_type_id}
because it makes more sense for me:
因为这对我来说更有意义
- there should not be duplicated "model names" for combination of "brand" and "fuel type", vs
- 对于“品牌”和“燃料类型”的组合,不应该有重复的“型号名称”
- there should not be duplicated "brands" for combination of "model name" and "fuel type"
- “车型名称”和“燃料类型”的组合不应重复使用“品牌”
but it's subjective opinion.
但它的主观意见。
Of course if brand and fuel_type are relationships to other models (if not, then just drop "_id" part). With uniqueness validation you can't check non-db columns, so you have to validate foreign keys in model.
当然,如果brand和fuel_type是与其他模型的关系(如果不是,那么只需删除“_id”部分)。对于唯一性验证,您不能检查非db列,因此必须在模型中验证外键。
You need to define which attribute is validated - you don't validate all at once, if you want, you need to create separate validation for every attribute, so when user make mistake and tries to create duplicated record, then you show him errors in form near invalid field.
您需要定义哪个属性是被验证的——如果您想要的话,您不能一次验证所有的属性,您需要为每个属性创建单独的验证,因此当用户出错并试图创建重复的记录时,您就会在无效字段附近显示他的错误。
#4
3
To Rails 4 the correct code with new hash pattern
对于Rails 4,使用新的散列模式进行正确的代码
validates :column_name, uniqueness: {scope: [:brand_id, :fuel_type_id]}
#5
2
Using this validation method in conjunction with ActiveRecord::Validations#save
does not guarantee the absence of duplicate record insertions, because uniqueness checks on the application level are inherently prone to race conditions.
与ActiveRecord::Validations#save一起使用这种验证方法并不保证没有重复的记录插入,因为应用程序级别上的惟一性检查天生容易出现竞争条件。
This could even happen if you use transactions with the 'serializable' isolation level. The best way to work around this problem is to add a unique index to the database table using ActiveRecord::ConnectionAdapters::SchemaStatements#add_index
. In the rare case that a race condition occurs, the database will guarantee the field's uniqueness.
如果您使用具有“serializable”隔离级别的事务,这甚至可能发生。解决这个问题的最佳方法是使用ActiveRecord:: connectionadapter:: schemastements #add_index向数据库表添加一个惟一的索引。在出现竞态条件的罕见情况下,数据库将保证字段的惟一性。
#1
92
There is a syntax error in your code snippet. The correct validation is :
代码片段中有一个语法错误。正确的验证是:
validates_uniqueness_of :car_model_name, :scope => [:brand_id, :fuel_type_id]
or even shorter in ruby 1.9.x:
或者更短的ruby 1.9.x:
validates_uniqueness_of :car_model_name, scope: [:brand_id, :fuel_type_id]
with rails 4 you can use:
使用rails 4,您可以使用:
validates :car_model_name, uniqueness: { scope: [:brand_id, :fuel_type_id] }
with rails 5 you can use
使用rails 5可以使用
validates_uniqueness_of :car_model_name, scope: %i[brand_id fuel_type_id]
#2
11
Depends on your needs you could also to add a constraint (as a part of table creation migration or as a separate one) instead of model validation:
根据您的需要,您还可以添加约束(作为表创建迁移的一部分或作为单独的约束),而不是模型验证:
add_index :the_table_name, [:brand, :model_name, :fuel_type], :unique => true
Adding the unique constraint on the database level makes sense, in case multiple database connections are performing write operations at the same time.
如果多个数据库连接同时执行写操作,那么在数据库级别上添加惟一约束是有意义的。
#3
4
I would make it this way:
我会这么做:
validates_uniqueness_of :model_name, :scope => {:brand_id, :fuel_type_id}
because it makes more sense for me:
因为这对我来说更有意义
- there should not be duplicated "model names" for combination of "brand" and "fuel type", vs
- 对于“品牌”和“燃料类型”的组合,不应该有重复的“型号名称”
- there should not be duplicated "brands" for combination of "model name" and "fuel type"
- “车型名称”和“燃料类型”的组合不应重复使用“品牌”
but it's subjective opinion.
但它的主观意见。
Of course if brand and fuel_type are relationships to other models (if not, then just drop "_id" part). With uniqueness validation you can't check non-db columns, so you have to validate foreign keys in model.
当然,如果brand和fuel_type是与其他模型的关系(如果不是,那么只需删除“_id”部分)。对于唯一性验证,您不能检查非db列,因此必须在模型中验证外键。
You need to define which attribute is validated - you don't validate all at once, if you want, you need to create separate validation for every attribute, so when user make mistake and tries to create duplicated record, then you show him errors in form near invalid field.
您需要定义哪个属性是被验证的——如果您想要的话,您不能一次验证所有的属性,您需要为每个属性创建单独的验证,因此当用户出错并试图创建重复的记录时,您就会在无效字段附近显示他的错误。
#4
3
To Rails 4 the correct code with new hash pattern
对于Rails 4,使用新的散列模式进行正确的代码
validates :column_name, uniqueness: {scope: [:brand_id, :fuel_type_id]}
#5
2
Using this validation method in conjunction with ActiveRecord::Validations#save
does not guarantee the absence of duplicate record insertions, because uniqueness checks on the application level are inherently prone to race conditions.
与ActiveRecord::Validations#save一起使用这种验证方法并不保证没有重复的记录插入,因为应用程序级别上的惟一性检查天生容易出现竞争条件。
This could even happen if you use transactions with the 'serializable' isolation level. The best way to work around this problem is to add a unique index to the database table using ActiveRecord::ConnectionAdapters::SchemaStatements#add_index
. In the rare case that a race condition occurs, the database will guarantee the field's uniqueness.
如果您使用具有“serializable”隔离级别的事务,这甚至可能发生。解决这个问题的最佳方法是使用ActiveRecord:: connectionadapter:: schemastements #add_index向数据库表添加一个惟一的索引。在出现竞态条件的罕见情况下,数据库将保证字段的惟一性。