Rubocop 唯一性验证应该使用唯一索引,在从某些特定值开始的值中

Posted

技术标签:

【中文标题】Rubocop 唯一性验证应该使用唯一索引,在从某些特定值开始的值中【英文标题】:Rubocop Uniqueness validation should be with a unique index, in values that start from some specific values 【发布时间】:2021-11-18 05:41:55 【问题描述】:

我有一个验证 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/enable Rubocop cmets 来修复它:

STARTING_NUMBER = 1_000_000

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

有没有更好的解决方案?

【问题讨论】:

我已经打开了一个 PR,看看我们是否可以改进对那个警察的描述,使其更清晰,这对你有帮助吗? github.com/rubocop/rubocop-rails/pull/563 谢谢@AndyWaite,是的,会很棒。 更新已合并。 【参考方案1】:

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

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

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


来自fine Rubocop manual:

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

Rubocop 发现您进行了唯一性验证,但未在您的 db/schema.rb 中找到相应的唯一索引。模型中的唯一性验证受竞争条件的影响,因此您仍然可以获得重复值。

Rubocop 告诉您在数据库中添加唯一索引/约束以确保唯一性。 Rails guides 也是这么说的:

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

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

不要抑制警告,解决它。

【讨论】:

谢谢你的详细解释,现在一切都清楚了。

以上是关于Rubocop 唯一性验证应该使用唯一索引,在从某些特定值开始的值中的主要内容,如果未能解决你的问题,请参考以下文章

唯一索引和普通索引

普通索引和唯一索引,应该怎么选择?

09 | 普通索引和唯一索引,应该怎么选择?

Mysql数据唯一约束与唯一索引案例总结及踩坑记(含NULL值与唯一约束唯一索引的搭配使用)

如何在vTiger crm 里加入字段的唯一性验证

#yyds干货盘点# MySQL的普通索引和唯一索引到底什么区别?