Ruby-on-rails Rails:验证 3 列的唯一组合

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7428872/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 01:58:21  来源:igfitidea点击:

Rails: Validate unique combination of 3 columns

ruby-on-railsruby-on-rails-3

提问by Niels Kristian

Hi I wan't to validate the unique combination of 3 columns in my table.

嗨,我不想验证表中 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.

应该都是有效的。但是另一条带有“Audi, A6, Gas”的记录不应该是有效的。

I know of this validation, but I doubt that it actually does what I want.

我知道这种验证,但我怀疑它是否真的符合我的要求。

    validates_uniqueness_of :brand, :scope => {:model_name, :fuel_type}

回答by alup

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 4you can use:

使用rails 4,您可以使用:

validates :car_model_name, uniqueness: { scope: [:brand_id, :fuel_type_id] }

with rails 5you can use

使用rails 5,您可以使用

validates_uniqueness_of :car_model_name, scope: %i[brand_id fuel_type_id]

回答by Alexander

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.

在数据库级别添加唯一约束是有意义的,以防多个数据库连接同时执行写操作。

回答by Ruby Junior Dev

To Rails 4 the correct code with new hash pattern

到 Rails 4 正确的代码和新的散列模式

validates :column_name, uniqueness: {scope: [:brand_id, :fuel_type_id]}

回答by MBO

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"
  • “品牌”和“燃料类型”的组合不应有重复的“型号名称”,vs
  • “型号名称”和“燃料类型”的组合不应有重复的“品牌”

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.

当然,如果品牌和燃料类型是与其他模型的关系(如果不是,则删除“_id”部分)。通过唯一性验证,您无法检查非数据库列,因此您必须验证模型中的外键。

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.

您需要定义验证哪个属性 - 您不会一次验证所有属性,如果需要,您需要为每个属性创建单独的验证,因此当用户出错并尝试创建重复记录时,您会向他显示错误无效字段附近的表单。

回答by imechemi

Using this validation method in conjunction with ActiveRecord::Validations#savedoes 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.

如果您使用具有“可序列化”隔离级别的事务,甚至可能会发生这种情况。解决此问题的最佳方法是使用 向数据库表添加唯一索引ActiveRecord::ConnectionAdapters::SchemaStatements#add_index。在极少数情况下发生竞争条件时,数据库将保证该字段的唯一性。

回答by Paul Lassiter

Piecing together the other answers and trying it myself, this is the syntax you're looking for:

validates :brand, uniqueness: { scope: [:model_name, :fuel_type] }

I'm not sure why the other answers are adding _idto the fields in the scope. That would only be needed if these fields are representing other models, but I didn't see an indication of that in the question. Additionally, these fields can be in any order. This will accomplish the same thing, only the error will be on the :model_nameattribute instead of :brand:

validates :model_name, uniqueness: { scope: [:fuel_type, :brand] }

将其他答案拼凑在一起并自己尝试,这就是您正在寻找的语法:

validates :brand, uniqueness: { scope: [:model_name, :fuel_type] }

我不确定为什么其他答案要添加_id到范围中的字段中。只有当这些字段代表其他模型时才需要这样做,但我在问题中没有看到这一点。此外,这些字段可以按任何顺序排列。这将完成同样的事情,只有错误会出现在:model_name属性而不是:brand

validates :model_name, uniqueness: { scope: [:fuel_type, :brand] }