From 13c29ccb8a0b8dd67b43eade88471848ab3544aa Mon Sep 17 00:00:00 2001 From: Aleksandar Ivanov Date: Mon, 19 Oct 2020 17:22:56 +0300 Subject: [PATCH 1/2] Do not pollute record changes when loading attributes for the first time This is done as in rails >= 5.2 the lock! & with_lock methods now require that the record doesn't have any changes otherwise they'll raise an error. https://github.com/rails/rails/blob/v5.2.4.4/activerecord/lib/active_record/locking/pessimistic.rb#L65 ``` def lock!(lock = true) if persisted? if has_changes_to_save? raise(<<-MSG.squish) Locking a record with unpersisted changes is not supported. Use `save` to persist the changes, or `reload` to discard them explicitly. MSG end reload(lock: lock) end self end ``` Apparently clear_attribute_changes receives an array of attributes which it should clear. https://apidock.com/rails/v5.2.3/ActiveModel/Dirty/clear_attribute_changes --- lib/vault/latest/encrypted_model.rb | 2 +- spec/integration/rails_spec.rb | 33 +++++++++++++++++++++-------- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/lib/vault/latest/encrypted_model.rb b/lib/vault/latest/encrypted_model.rb index 8e884543..40b22fd1 100644 --- a/lib/vault/latest/encrypted_model.rb +++ b/lib/vault/latest/encrypted_model.rb @@ -329,7 +329,7 @@ def __vault_load_attribute!(attribute, options) __vault_loaded_attributes << attribute # Write the virtual attribute with the plaintext value - write_attribute(attribute, plaintext) + write_attribute(attribute, plaintext).tap { clear_attribute_changes([attribute]) } end # Encrypt all the attributes using Vault and set the encrypted values back diff --git a/spec/integration/rails_spec.rb b/spec/integration/rails_spec.rb index 9ad8c8a0..8c5eeebd 100644 --- a/spec/integration/rails_spec.rb +++ b/spec/integration/rails_spec.rb @@ -40,6 +40,12 @@ expect(person.ssn_was).to eq("123-45-6789") end + it 'does not pollute changes / dirty attributes / when loading a record from the db' do + Person.create!(ssn: "123-45-6789") + + expect(Person.last.changes).to be_blank + end + it "allows attributes to be updated with nil values" do person = Person.create!(ssn: "123-45-6789") person.update_attributes!(ssn: nil) @@ -175,6 +181,15 @@ expect(person.ssn_was).to eq("123-45-6789") end + it 'does not pollute changes / dirty attributes / when loading a record from the db' do + Person.create!(ssn: "123-45-6789") + + person = Person.last + expect(person.changes).to be_blank + expect(person.ssn).to eq('123-45-6789') + expect(person.changes).to be_blank + end + it "allows attributes to be unset" do person = LazyPerson.create!(ssn: "123-45-6789") person.update_attributes!(ssn: nil) @@ -572,7 +587,7 @@ context 'attribute with defined serializer' do context 'new record with duplicated IP address' do it 'is invalid' do - person = Person.create!(ip_address: IPAddr.new('127.0.0.1')) + Person.create!(ip_address: IPAddr.new('127.0.0.1')) same_ip_address_person = Person.new(ip_address: IPAddr.new('127.0.0.1')) expect(same_ip_address_person).not_to be_valid @@ -670,8 +685,8 @@ it 'finds the expected record' do first_person = LazyPerson.create!(passport_number: '12345678') - second_person = LazyPerson.create!(passport_number: '12345678') - third_person = LazyPerson.create!(passport_number: '87654321') + LazyPerson.create!(passport_number: '12345678') + LazyPerson.create!(passport_number: '87654321') expect(LazyPerson.encrypted_find_by(passport_number: '12345678')).to eq(first_person) end @@ -679,7 +694,7 @@ context 'searching by attributes with defined serializer' do it 'finds the expected record' do first_person = Person.create!(ip_address: IPAddr.new('127.0.0.1')) - second_person = Person.create!(ip_address: IPAddr.new('192.168.0.1')) + Person.create!(ip_address: IPAddr.new('192.168.0.1')) expect(Person.encrypted_find_by(ip_address: IPAddr.new('127.0.0.1'))).to eq(first_person) end @@ -707,8 +722,8 @@ it 'finds the expected record' do first_person = LazyPerson.create!(passport_number: '12345678') - second_person = LazyPerson.create!(passport_number: '12345678') - third_person = LazyPerson.create!(passport_number: '87654321') + LazyPerson.create!(passport_number: '12345678') + LazyPerson.create!(passport_number: '87654321') expect(LazyPerson.encrypted_find_by!(passport_number: '12345678')).to eq(first_person) end @@ -716,7 +731,7 @@ context 'searching by attributes with defined serializer' do it 'finds the expected record' do first_person = Person.create!(ip_address: IPAddr.new('127.0.0.1')) - second_person = Person.create!(ip_address: IPAddr.new('192.168.0.1')) + Person.create!(ip_address: IPAddr.new('192.168.0.1')) expect(Person.encrypted_find_by!(ip_address: IPAddr.new('127.0.0.1'))).to eq(first_person) end @@ -751,7 +766,7 @@ it 'finds the expected records' do first_person = LazyPerson.create!(passport_number: '12345678') second_person = LazyPerson.create!(passport_number: '12345678') - third_person = LazyPerson.create!(passport_number: '87654321') + LazyPerson.create!(passport_number: '87654321') expect(LazyPerson.encrypted_where(passport_number: '12345678').pluck(:id)).to match_array([first_person, second_person].map(&:id)) end @@ -759,7 +774,7 @@ context 'searching by attributes with defined serializer' do it 'finds the expected records' do first_person = Person.create!(ip_address: IPAddr.new('127.0.0.1')) - second_person = Person.create!(ip_address: IPAddr.new('192.168.0.1')) + Person.create!(ip_address: IPAddr.new('192.168.0.1')) expect(Person.encrypted_where(ip_address: IPAddr.new('127.0.0.1')).pluck(:id)).to match_array([first_person.id]) end From 12349291303a3adcc00a1e53ef4bd0cbabd169e0 Mon Sep 17 00:00:00 2001 From: Aleksandar Ivanov Date: Mon, 19 Oct 2020 17:54:41 +0300 Subject: [PATCH 2/2] Bump version to 2.0.5 --- CHANGELOG.md | 7 +++++++ gemfiles/rails_4.2.gemfile.lock | 2 +- gemfiles/rails_5.0.gemfile.lock | 2 +- gemfiles/rails_5.1.gemfile.lock | 2 +- gemfiles/rails_5.2.gemfile.lock | 2 +- gemfiles/rails_6.gemfile.lock | 2 +- lib/vault/rails/version.rb | 2 +- 7 files changed, 13 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2a86b953..6837f84b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Vault Rails Changelog +## 2.0.5 (October 19, 2020) + +- Fix compatibility with `#with_lock` / `#lock!` - on initialization the `#changes` is no longer polluted. Fixed error: +``` +RuntimeError: Locking a record with unpersisted changes is not supported. Use `save` to persist the changes, or `reload` to discard them explicitly. +``` + ## 2.0.4 (December 2, 2019) IMPROVEMENTS diff --git a/gemfiles/rails_4.2.gemfile.lock b/gemfiles/rails_4.2.gemfile.lock index dc49073a..3095d47c 100644 --- a/gemfiles/rails_4.2.gemfile.lock +++ b/gemfiles/rails_4.2.gemfile.lock @@ -1,7 +1,7 @@ PATH remote: .. specs: - fc-vault-rails (2.0.4) + fc-vault-rails (2.0.5) activerecord (>= 4.2) vault (~> 0.7) diff --git a/gemfiles/rails_5.0.gemfile.lock b/gemfiles/rails_5.0.gemfile.lock index 2019a9d4..e72770ba 100644 --- a/gemfiles/rails_5.0.gemfile.lock +++ b/gemfiles/rails_5.0.gemfile.lock @@ -1,7 +1,7 @@ PATH remote: .. specs: - fc-vault-rails (2.0.4) + fc-vault-rails (2.0.5) activerecord (>= 4.2) vault (~> 0.7) diff --git a/gemfiles/rails_5.1.gemfile.lock b/gemfiles/rails_5.1.gemfile.lock index fdcbda30..c631f523 100644 --- a/gemfiles/rails_5.1.gemfile.lock +++ b/gemfiles/rails_5.1.gemfile.lock @@ -1,7 +1,7 @@ PATH remote: .. specs: - fc-vault-rails (2.0.4) + fc-vault-rails (2.0.5) activerecord (>= 4.2) vault (~> 0.7) diff --git a/gemfiles/rails_5.2.gemfile.lock b/gemfiles/rails_5.2.gemfile.lock index 2a7c0ce0..8214692d 100644 --- a/gemfiles/rails_5.2.gemfile.lock +++ b/gemfiles/rails_5.2.gemfile.lock @@ -1,7 +1,7 @@ PATH remote: .. specs: - fc-vault-rails (2.0.4) + fc-vault-rails (2.0.5) activerecord (>= 4.2) vault (~> 0.7) diff --git a/gemfiles/rails_6.gemfile.lock b/gemfiles/rails_6.gemfile.lock index e3009ab8..ce3750f3 100644 --- a/gemfiles/rails_6.gemfile.lock +++ b/gemfiles/rails_6.gemfile.lock @@ -1,7 +1,7 @@ PATH remote: .. specs: - fc-vault-rails (2.0.4) + fc-vault-rails (2.0.5) activerecord (>= 4.2) vault (~> 0.7) diff --git a/lib/vault/rails/version.rb b/lib/vault/rails/version.rb index e8b6554e..0fd157dc 100644 --- a/lib/vault/rails/version.rb +++ b/lib/vault/rails/version.rb @@ -1,6 +1,6 @@ module Vault module Rails - VERSION = "2.0.4" + VERSION = "2.0.5" def self.latest? ActiveRecord.version >= Gem::Version.new('5.0.0')