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

Ruby on rails Rails:验证3列的唯一组合,ruby-on-rails,ruby-on-rails-3,Ruby On Rails,Ruby On Rails 3,嗨,我不想验证表中3列的唯一组合 假设我有一个名为cars的表,其值为:brand、:model\u name和:fuel\u type 然后,我想验证的是,根据这三个参数的组合,记录是否唯一。例如: brand model_name fuel_type Audi A4 Gas Audi A4 Diesel Audi A6 Gas 都应该是有效的。但另一项“奥迪

嗨,我不想验证表中3列的唯一组合

假设我有一个名为cars的表,其值为:brand、:model\u name和:fuel\u type

然后,我想验证的是,根据这三个参数的组合,记录是否唯一。例如:

    brand    model_name    fuel_type
    Audi     A4            Gas
    Audi     A4            Diesel
    Audi     A6            Gas
都应该是有效的。但另一项“奥迪A6汽油”的记录应该无效

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

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

我会这样做:

validates_uniqueness_of :model_name, :scope => {:brand_id, :fuel_type_id}
因为这对我来说更有意义:

  • 对于“品牌”和“燃料类型”的组合,与
  • “型号名称”和“燃料类型”的组合不应有重复的“品牌”
但这是主观意见

当然,如果品牌和燃料类型与其他车型相关(如果不是,则只需删除“\u id”部分)。使用唯一性验证时,您无法检查非db列,所以必须验证模型中的外键


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

代码段中存在语法错误。正确的验证是:

validates_uniqueness_of :car_model_name, :scope => [:brand_id, :fuel_type_id]
在ruby 1.9.x中甚至更短:

validates_uniqueness_of :car_model_name, scope: [:brand_id, :fuel_type_id]
使用rails 4,您可以使用:

validates :car_model_name, uniqueness: { scope: [:brand_id, :fuel_type_id] }
使用rails 5,您可以使用

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

根据您的需要,您还可以添加约束(作为表创建迁移的一部分或作为单独的约束),而不是模型验证:

add_index :the_table_name, [:brand, :model_name, :fuel_type], :unique => true

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

使用新的哈希模式将正确的代码添加到Rails 4

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

将此验证方法与
ActiveRecord::Validations#save
结合使用并不保证没有重复的记录插入,因为应用程序级别上的唯一性检查本质上容易出现竞争条件


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

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

验证:品牌、唯一性:{scope:[:model\u name,:fuel\u type]}


我不知道为什么其他答案会将
\u id
添加到范围中的字段中。只有当这些字段代表其他模型时才需要这样做,但我在问题中没有看到这方面的迹象。此外,这些字段可以是任意顺序。这将完成同样的事情,只有
:model_name
属性上的错误,而不是
:brand



验证:型号名称,唯一性:{scope:[:燃料类型,:品牌]}

不要怀疑。你的验证是正确的嗯,好吧-只是想检查一下:品牌在一个组中是否是唯一的:model_name,:fuel_type可能重复rails 4示例是否正确?我认为应该是这样的:
验证:品牌标识,唯一性:{scope:[:fuel\u type\u id]}
(即,不要引用车型名称)。:车型名称引用OP关于车型的问题lol而不是车型类别:POh是的,这是误导性的:(嗨,我想你是对的,但我不清楚逻辑是如何运作的。我对“每种品牌和燃料类型的独特品牌”有一种确认的感觉,但我不明白为什么说“每种型号和燃料类型的独特品牌”是错的嗯。是的,我和@tidelake有同样的问题。为什么每个回答都说用
验证模型名称
:范围=>{:brand\u id,:fuel\u type\u id}?为什么不用前面提到的方法验证
:brand
:范围=>{:model\u name,:fuel\u type}
?为什么建议的顺序与OP的问题不同?我不知道问题是什么,也不知道所有答案都说要验证
模型名称而不是
品牌
!!!当我尝试此操作时,它对所有列单独施加的唯一约束似乎是有效的,但是如果有人试图保存重复的条目e服务器将响应一个内部服务器错误(500)消息,这不是所需的行为。为了避免这种情况,您需要在模型级别添加验证,这样它将像任何其他验证一样以错误消息响应。@tafuentesc您可以编写控制器,以便决定服务器响应的内容。您可以用
rescue
包装代码(尝试捕获)并以您想要的方式对重复错误进行响应。正如@tafuentesc提到的,强烈建议在模型中添加验证,以防止引发
ActiveRecord::RecordNotUnique
错误,至少在Rails 5中是这样。验证可能类似于
validates\u university\u of:model\u name,scope:%i[fuel\u type brand],消息:“给定名称已存在”