首页 > 解决方案 > Rubocop 唯一性验证应该使用唯一索引,在从某些特定值开始的值中

问题描述

我有一个验证 order_number 值唯一性的 rails 模型,应该从 1_000_000 开始,所以我添加了一个用作第一个值的变量:

# order model 
STARTING_NUMBER = 1_000_000

validates :order_number, uniqueness: true

当我通过 Rubocop 检查我的代码时,我遇到了一个错误:

app/models/order.rb:3:3: C: Rails/UniqueValidationWithoutIndex: Uniqueness validation should be with a unique index.
  validates :order_number, uniqueness: true

我通过添加disable/enableRubocop 评论来修复它:

STARTING_NUMBER = 1_000_000

# rubocop:disable Rails/UniqueValidationWithoutIndex
validates :order_number, uniqueness: true
# rubocop:enable Rails/UniqueValidationWithoutIndex

有更好的解决方案吗?

标签: ruby-on-railsrubyrails-activerecordactivemodelrubocop

解决方案


正确的解决方法是通过迁移向数据库添加唯一索引:

def change
  add_index :orders, :order_number, unique: true
end

这将解决根本问题并防止 Rubocop 抱怨。


来自精美的 Rubocop 手册

在 Active Record 模型中定义唯一性验证时,还应该为列添加唯一索引。有两个原因首先,即使定义了 Active Record 的验证,也可能出现重复记录。其次,会导致查询慢。

Rubocop 发现您有一个唯一性验证,但没有在您的db/schema.rb. 模型中的唯一性验证受竞争条件的影响,因此您仍然可以获得重复值。

Rubocop 告诉您在数据库中添加唯一索引/约束以确保唯一性。Rails 指南说同样的话:

它不会在数据库中创建唯一性约束,因此可能会发生两个不同的数据库连接为您打算唯一的列创建具有相同值的两条记录。为避免这种情况,您必须在数据库中的该列上创建唯一索引。

验证还将执行潜在的昂贵数据库查询,因此无论如何您确实希望对该列进行索引,不妨将其设为唯一索引以确保您使用它时的数据完整性(损坏的代码是临时的,损坏的数据是永远的)。

不要压制警告,解决它。


推荐阅读