diff options
author | Ryuta Kamizono <kamipo@gmail.com> | 2018-05-19 20:39:52 +0900 |
---|---|---|
committer | Ryuta Kamizono <kamipo@gmail.com> | 2018-05-25 23:55:38 +0900 |
commit | 8a600183550298a1f350a8fa8d72630da607fb60 (patch) | |
tree | 31d1b57cd110c16255a9faeeae89569634b61018 | |
parent | cd4a88123dc17462d5c2ff29172b0366bca14e0e (diff) | |
download | rails-8a600183550298a1f350a8fa8d72630da607fb60.tar.gz rails-8a600183550298a1f350a8fa8d72630da607fb60.tar.bz2 rails-8a600183550298a1f350a8fa8d72630da607fb60.zip |
Make force equality checking more strictly not to allow serialized attribute
Since #26074, introduced force equality checking to build a predicate
consistently for both `find` and `create` (fixes #27313).
But the assumption that only array/range attribute have subtype was
wrong. We need to make force equality checking more strictly not to
allow serialized attribute.
Fixes #32761.
6 files changed, 32 insertions, 5 deletions
diff --git a/activemodel/lib/active_model/type/value.rb b/activemodel/lib/active_model/type/value.rb index a8ea6a2c22..b6914dd63c 100644 --- a/activemodel/lib/active_model/type/value.rb +++ b/activemodel/lib/active_model/type/value.rb @@ -90,6 +90,10 @@ module ActiveModel false end + def force_equality?(_value) # :nodoc: + false + end + def map(value) # :nodoc: yield value end diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb index d6852082ac..26abeea7ed 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/array.rb @@ -66,6 +66,10 @@ module ActiveRecord deserialize(raw_old_value) != new_value end + def force_equality?(value) + value.is_a?(::Array) + end + private def type_cast_array(value, method) diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb index 6edb7cfd3c..d85f9ab3ef 100644 --- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb +++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/range.rb @@ -53,6 +53,10 @@ module ActiveRecord ::Range.new(new_begin, new_end, value.exclude_end?) end + def force_equality?(value) + value.is_a?(::Range) + end + private def type_cast_single(value) diff --git a/activerecord/lib/active_record/relation/predicate_builder.rb b/activerecord/lib/active_record/relation/predicate_builder.rb index 7a0edcbc33..4a4ceca782 100644 --- a/activerecord/lib/active_record/relation/predicate_builder.rb +++ b/activerecord/lib/active_record/relation/predicate_builder.rb @@ -48,7 +48,13 @@ module ActiveRecord end def build(attribute, value) - handler_for(value).call(attribute, value) + # FIXME: Deprecate this and provide a public API to force equality + if table.type(attribute.name).force_equality?(value) + bind = build_bind_attribute(attribute.name, value) + attribute.eq(bind) + else + handler_for(value).call(attribute, value) + end end def build_bind_attribute(column_name, value) @@ -95,10 +101,6 @@ module ActiveRecord end.reduce(&:and) end queries.reduce(&:or) - # FIXME: Deprecate this and provide a public API to force equality - elsif (value.is_a?(Range) || value.is_a?(Array)) && - table.type(key.to_s).respond_to?(:subtype) - BasicObjectHandler.new(self).call(table.arel_attribute(key), value) else build(table.arel_attribute(key), value) end diff --git a/activerecord/test/cases/adapters/postgresql/range_test.rb b/activerecord/test/cases/adapters/postgresql/range_test.rb index 261c24634e..433598500d 100644 --- a/activerecord/test/cases/adapters/postgresql/range_test.rb +++ b/activerecord/test/cases/adapters/postgresql/range_test.rb @@ -341,6 +341,12 @@ _SQL assert_equal record, PostgresqlRange.where(int4_range: range).take end + def test_where_by_attribute_with_range_in_array + range = 1..100 + record = PostgresqlRange.create!(int4_range: range) + assert_equal record, PostgresqlRange.where(int4_range: [range]).take + end + def test_update_all_with_ranges PostgresqlRange.create! diff --git a/activerecord/test/cases/serialized_attribute_test.rb b/activerecord/test/cases/serialized_attribute_test.rb index 7de5429cbb..7764a37273 100644 --- a/activerecord/test/cases/serialized_attribute_test.rb +++ b/activerecord/test/cases/serialized_attribute_test.rb @@ -166,6 +166,13 @@ class SerializedAttributeTest < ActiveRecord::TestCase assert_equal topic, Topic.where(content: settings).take end + def test_where_by_serialized_attribute_with_hash_in_array + settings = { "color" => "green" } + Topic.serialize(:content, Hash) + topic = Topic.create!(content: settings) + assert_equal topic, Topic.where(content: [settings]).take + end + def test_serialized_default_class Topic.serialize(:content, Hash) topic = Topic.new |