I have a rails model that validates the uniqueness of order_number value, id 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?
CodePudding user response:
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.