Rubocop Uniqueness validation should be with a unique index, in values that start from some specific values
Asked Answered
T

1

8

I have a rails model that validates the uniqueness of order_number value, thay should start from 1_000_000, so I added a variable that is used as a first value:

# order model 
STARTING_NUMBER = 1_000_000

validates :order_number, uniqueness: true

When I checked my code by Rubocop I had an error:

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

I fixed it by adding disable/enable Rubocop comments:

STARTING_NUMBER = 1_000_000

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

Is there a better solution?

Thracian answered 25/9, 2021 at 5:42 Comment(3)
I've opened a PR to see if we can improve the description of that cop to make it clearer, would this have helped you? github.com/rubocop/rubocop-rails/pull/563Co
Thank you @AndyWaite, yes it would be great.Thracian
The update has been merged.Co
D
14

The proper fix is to add a unique index to your database with a migration:

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

That will fix the underlying problem and keep Rubocop from complaining.


From the fine Rubocop manual:

When you define a uniqueness validation in Active Record model, you also should add a unique index for the column. There are two reasons First, duplicated records may occur even if Active Record’s validation is defined. Second, it will cause slow queries.

Rubocop sees that you have a uniqueness validation but didn't find a corresponding unique index in your db/schema.rb. A uniqueness validation in a model is subject to race conditions so you can still get duplicate values.

Rubocop is telling you to add a unique index/constraint in the database to ensure uniqueness. The Rails guides say the same thing:

It does not create a uniqueness constraint in the database, so it may happen that two different database connections create two records with the same value for a column that you intend to be unique. To avoid that, you must create a unique index on that column in your database.

The validation will also do a potentially expensive database query so you really want to index that column anyway, might as well make it a unique index to ensure data integrity while you're at it (broken code is temporary, broken data is forever).

Don't suppress the warning, address it.

Descombes answered 25/9, 2021 at 17:36 Comment(1)
Thank you for the detailed explanation, now everything is clear.Thracian

© 2022 - 2024 — McMap. All rights reserved.