Database based uniqueness validations for ActiveRecord
You may have noticed that Rails is performing a SELECT 1 FROMquery before inserting a new record if there's a uniqueness validation in the model.
This approach has several downsides.
First of all, it's an additional query, and in case there's uniqueness validation on several attributes, several additional queries will be performed.
Second, which is important for applications running at scale, is a race condition, two concurrent create/update operations may end up querying the database for existing records and then add a record to the database that will leave it in an inconsistent state. Of course, this may be resolved with a DB uniqueness constraint, but in this case, you won't get a proper validation message, the request will just error out.
Welcome database_validations gem, which provides compatibility between database constraints and ActiveRecord validations with better performance and consistency.
Skip to the benchmarks to find out that for the case where each hundredth statement is attempting to insert a duplicate is two times faster with this gem.
In majority of cases, validates_db_uniqueness_of is a drop-in replacement for validates_uniqueness_of.
scope, message, if and unless conditionals and index_name are supported on major databases. where is supported on PostgreSQL.
A convenience RSpec matcher is bundled:
specify do expect(described_class).to validate_db_uniqueness_of(:field) .with_message('duplicate') .with_where('(some_field IS NULL)') .scoped_to(:another_field) .with_index(:unique_index) end
You must add DB uniqueness constraints on the database level, and if you didn't, the gem will error out with an explanatory message.
The gem is battle tested on an application with almost a hundred uniqueness validations in 50+ models at scale.
if there's more than one validation failure, only one will be indicated