From 4c7832ce2a0ed3f05c466fa3602ad1f29c2f945e Mon Sep 17 00:00:00 2001 From: Aitor Lopez Beltran Date: Tue, 27 Oct 2026 09:52:02 +0000 Subject: [PATCH 1/3] [CASE-4447] Fix the two RuboCop offenses on master --- database_validations.gemspec | 2 +- spec/validations/db_belongs_to_spec.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/database_validations.gemspec b/database_validations.gemspec index fdd4a4a..1fe9a4f 100644 --- a/database_validations.gemspec +++ b/database_validations.gemspec @@ -9,7 +9,7 @@ Gem::Specification.new do |spec| spec.email = ['lawliet.djez@gmail.com'] spec.summary = 'Provide compatibility between database constraints and ActiveRecord validations with better performance and consistency.' - spec.description = "ActiveRecord provides validations on app level but it won't guarantee the + spec.description = "ActiveRecord provides validations on app level but it won't guarantee the consistent. In some cases, like `validates_uniqueness_of` it executes additional SQL query to the database and that is not very efficient. diff --git a/spec/validations/db_belongs_to_spec.rb b/spec/validations/db_belongs_to_spec.rb index 2cbdd53..a320a69 100644 --- a/spec/validations/db_belongs_to_spec.rb +++ b/spec/validations/db_belongs_to_spec.rb @@ -142,7 +142,7 @@ def define_tables end end - describe 'multiple db_belongs_to associations' do # rubocop:disable RSpec/MultipleMemoizedHelpers: + describe 'multiple db_belongs_to associations' do # rubocop:disable RSpec/MultipleMemoizedHelpers let(:department_klass) { define_class(Department, :departments) } let(:multi_fk_klass) do From 5903952b010b18019a2758ec90664c340764ddcd Mon Sep 17 00:00:00 2001 From: Aitor Lopez Beltran Date: Tue, 27 Oct 2026 09:52:02 +0000 Subject: [PATCH 2/3] [CASE-4447] Leave Rails 8.2's existing_id out of the saved-error comparison Rails main (8.2.0.alpha, rails/rails@03a3ed8397) adds the conflicting record's id to the uniqueness error details. On save the error comes from the database, which does not report the id, so the comparison with Rails' own validator failed in the railsmaster job (62 examples). --- spec/validations/validates_db_uniqueness_of_spec.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/spec/validations/validates_db_uniqueness_of_spec.rb b/spec/validations/validates_db_uniqueness_of_spec.rb index 72321b2..5713881 100644 --- a/spec/validations/validates_db_uniqueness_of_spec.rb +++ b/spec/validations/validates_db_uniqueness_of_spec.rb @@ -8,6 +8,13 @@ before { parent_class.create!(persisted_attrs) unless skip_persisted } + # Rails main (8.2.0.alpha) adds the conflicting record's id to uniqueness error details as `existing_id`. + # db_uniqueness's error on save comes from the unique violation, which carries no id, so the id is taken out + # of app_uniqueness's details before comparing. + def details_without_existing_id(record) + record.errors.details.to_h.transform_values { |details| details.map { |detail| detail.except(:existing_id) } } + end + describe 'valid?' do it 'makes a query for validation' do expect { db_uniqueness.new(persisted_attrs).valid? } @@ -74,7 +81,7 @@ expect(new.errors.details).to be_present expect(old.errors.messages.to_h).to include(new.errors.messages.to_h) - expect(old.errors.details.to_h).to include(new.errors.details.to_h) + expect(details_without_existing_id(old)).to include(new.errors.details.to_h) end context 'when wrapped by transaction' do @@ -91,7 +98,7 @@ expect(new.errors.details).to be_present expect(old.errors.messages.to_h).to include(new.errors.messages.to_h) - expect(old.errors.details.to_h).to include(new.errors.details.to_h) + expect(details_without_existing_id(old)).to include(new.errors.details.to_h) end end end From 0e97ecbe1cc688d4a551a89be6e30c4db93e3387 Mon Sep 17 00:00:00 2001 From: Aitor Lopez Beltran Date: Tue, 27 Oct 2026 09:52:02 +0000 Subject: [PATCH 3/3] [CASE-4447] Version 2.1.2 is released --- CHANGELOG.md | 4 +++- lib/database_validations/version.rb | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7c7d38b..ef0d350 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,9 @@ # Changelog ## Unreleased - xxxx-xx-xx -- `db_belongs_to` handles a violated composite foreign key on PostgreSQL. Its error names every column of the key, `Key (tenant_id, company_id)`; each is now a candidate, so the association's `must exist` error is added instead of the exception being raised + +## [2.1.2] - 2026-10-27 +- Fix `db_belongs_to` raising `ActiveRecord::InvalidForeignKey` for a violated composite foreign key on PostgreSQL. Its error names every column of the key, `Key (tenant_id, company_id)`; each is now a candidate, so the association's `must exist` error is added instead - Fix `validates_db_uniqueness_of` raising `NoMethodError` on PostgreSQL when the table has row-level security. PostgreSQL omits the `Key (...)=(...)` detail from the unique violation there, so the error is now matched by its index name only ## [2.1.1] - 2026-03-31 diff --git a/lib/database_validations/version.rb b/lib/database_validations/version.rb index ec67b64..8da962d 100644 --- a/lib/database_validations/version.rb +++ b/lib/database_validations/version.rb @@ -1,3 +1,3 @@ module DatabaseValidations - VERSION = '2.1.1'.freeze + VERSION = '2.1.2'.freeze end