it-swarm.cn

Rails:验证3列的唯一组合

嗨,我不想在我的表中验证3列的独特组合。

假设我有一个名为cars的表,其值为:brand,:model_name和:fuel_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}
54
Niels Kristian

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

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]
97
alup

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

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

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

14
Alexander

我会这样做:

validates_uniqueness_of :model_name, :scope => {:brand_id, :fuel_type_id}

因为它对我来说更有意义:

  • 对于“品牌”和“燃料类型”的组合,不应该有重复的“型号名称”
  • 对于“型号名称”和“燃料类型”的组合,不应该有重复的“品牌”

但这是主观意见。

当然,如果brand和fuel_type是与其他模型的关系(如果没有,那么只需删除“_id”部分)。使用唯一性验证,您无法检查非db列,因此您必须验证模型中的外键。

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

4
MBO

使用新的哈希模式为Rails 4提供正确的代码

validates :column_name, uniqueness: {scope: [:brand_id, :fuel_type_id]}
4
Ruby Junior Dev

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

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

2
imechemi