From 8ded825bc29338d1a2ae7c3a2119cfa301008f85 Mon Sep 17 00:00:00 2001 From: Jon Moss Date: Fri, 30 Dec 2016 18:43:04 -0500 Subject: Compare deserialized values for `PostgreSQL::OID::Hstore` types Per the regression commit below, the commit changes the behavior of `#changed?`to consult the `#changed_in_place?` method on `Type::Value` classes. Per this change, `PostgreSQL::OID::Hstore` needs to override this method in order to compare the deserialized forms of the two arguments. In Ruby, two hashes are considered equal even if their key order is different. This commit helps to bring that behavior to `Hstore` values. Fixes regression introduced by 8e633e505880755e7e366ccec2210bbe2b5436e7 Fixes #27502 --- activerecord/CHANGELOG.md | 7 +++++++ .../connection_adapters/postgresql/oid/hstore.rb | 8 ++++++++ .../test/cases/adapters/postgresql/hstore_test.rb | 19 +++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md index 00d1a7a623..743a38b087 100644 --- a/activerecord/CHANGELOG.md +++ b/activerecord/CHANGELOG.md @@ -1,3 +1,10 @@ +* Compare deserialized values for `PostgreSQL::OID::Hstore` types when + calling `ActiveRecord::Dirty#changed_in_place?` + + Fixes #27502. + + *Jon Moss* + * Raise `ArgumentError` when passing an `ActiveRecord::Base` instance to `.find` and `.exists?`. diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb index d629ebca91..49dd4fc73f 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/hstore.rb @@ -35,6 +35,14 @@ module ActiveRecord ActiveRecord::Store::StringKeyedHashAccessor end + # Will compare the Hash equivalents of +raw_old_value+ and +new_value+. + # By comparing hashes, this avoids an edge case where the order of + # the keys change between the two hashes, and they would not be marked + # as equal. + def changed_in_place?(raw_old_value, new_value) + deserialize(raw_old_value) != new_value + end + private HstorePair = begin diff --git a/activerecord/test/cases/adapters/postgresql/hstore_test.rb b/activerecord/test/cases/adapters/postgresql/hstore_test.rb index 1f35300739..f9cce10fb8 100644 --- a/activerecord/test/cases/adapters/postgresql/hstore_test.rb +++ b/activerecord/test/cases/adapters/postgresql/hstore_test.rb @@ -171,6 +171,25 @@ if ActiveRecord::Base.connection.supports_extensions? assert_not hstore.changed? end + def test_dirty_from_user_equal + settings = { "alongkey" => "anything", "key" => "value" } + hstore = Hstore.create!(settings: settings) + + hstore.settings = { "key" => "value", "alongkey" => "anything" } + assert_equal settings, hstore.settings + refute hstore.changed? + end + + def test_hstore_dirty_from_database_equal + settings = { "alongkey" => "anything", "key" => "value" } + hstore = Hstore.create!(settings: settings) + hstore.reload + + assert_equal settings, hstore.settings + hstore.settings = settings + refute hstore.changed? + end + def test_gen1 assert_equal('" "=>""', @type.serialize(" " => "")) end -- cgit v1.2.3