aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Griffin <sean@seantheprogrammer.com>2017-08-04 18:05:00 -0400
committerGitHub <noreply@github.com>2017-08-04 18:05:00 -0400
commit978b3d604ab082ac0be071245646b0803b8ff382 (patch)
treef5f1389971e16e564d8657aaeb2b18226e0dc91e
parent6453b0e50aeb46e1eef056c4cd29eaee2ebf9c43 (diff)
parenta0751d27c52185b86370baf6a565e757092646de (diff)
downloadrails-978b3d604ab082ac0be071245646b0803b8ff382.tar.gz
rails-978b3d604ab082ac0be071245646b0803b8ff382.tar.bz2
rails-978b3d604ab082ac0be071245646b0803b8ff382.zip
Merge pull request #29520 from kirs/serialize-vs-postgres-native-column
Do not let use `serialize` on native JSON/array column
-rw-r--r--activerecord/lib/active_record/attribute_methods/serialization.rb24
-rw-r--r--activerecord/test/cases/adapters/postgresql/array_test.rb9
-rw-r--r--activerecord/test/cases/adapters/postgresql/json_test.rb9
3 files changed, 42 insertions, 0 deletions
diff --git a/activerecord/lib/active_record/attribute_methods/serialization.rb b/activerecord/lib/active_record/attribute_methods/serialization.rb
index 6ed45d8737..acd47629dd 100644
--- a/activerecord/lib/active_record/attribute_methods/serialization.rb
+++ b/activerecord/lib/active_record/attribute_methods/serialization.rb
@@ -5,6 +5,16 @@ module ActiveRecord
module Serialization
extend ActiveSupport::Concern
+ class ColumnNotSerializableError < StandardError
+ def initialize(name, type)
+ super <<-EOS.strip_heredoc
+ Column `#{name}` of type #{type.class} does not support `serialize` feature.
+ Usually it means that you are trying to use `serialize`
+ on a column that already implements serialization natively.
+ EOS
+ end
+ end
+
module ClassMethods
# If you have an attribute that needs to be saved to the database as an
# object, and retrieved as the same object, then specify the name of that
@@ -60,9 +70,23 @@ module ActiveRecord
end
decorate_attribute_type(attr_name, :serialize) do |type|
+ if type_incompatible_with_serialize?(type)
+ raise ColumnNotSerializableError.new(attr_name, type)
+ end
+
Type::Serialized.new(type, coder)
end
end
+
+ private
+
+ def type_incompatible_with_serialize?(type)
+ type.is_a?(ActiveRecord::Type::Json) ||
+ (
+ defined?(ActiveRecord::ConnectionAdapters::PostgreSQL) &&
+ type.is_a?(ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array)
+ )
+ end
end
end
end
diff --git a/activerecord/test/cases/adapters/postgresql/array_test.rb b/activerecord/test/cases/adapters/postgresql/array_test.rb
index 8507dbb463..08b17f37e2 100644
--- a/activerecord/test/cases/adapters/postgresql/array_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/array_test.rb
@@ -47,6 +47,15 @@ class PostgresqlArrayTest < ActiveRecord::PostgreSQLTestCase
assert ratings_column.array?
end
+ def test_not_compatible_with_serialize
+ new_klass = Class.new(PgArray) do
+ serialize :tags, Array
+ end
+ assert_raises(ActiveRecord::AttributeMethods::Serialization::ColumnNotSerializableError) do
+ new_klass.new
+ end
+ end
+
def test_default
@connection.add_column "pg_arrays", "score", :integer, array: true, default: [4, 4, 2]
PgArray.reset_column_information
diff --git a/activerecord/test/cases/adapters/postgresql/json_test.rb b/activerecord/test/cases/adapters/postgresql/json_test.rb
index aa5e03df41..79dcfe110c 100644
--- a/activerecord/test/cases/adapters/postgresql/json_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/json_test.rb
@@ -33,6 +33,15 @@ module PostgresqlJSONSharedTestCases
x.reload
assert_equal ["foo" => "bar"], x.objects
end
+
+ def test_not_compatible_with_serialize_macro
+ new_klass = Class.new(klass) do
+ serialize :payload, JSON
+ end
+ assert_raises(ActiveRecord::AttributeMethods::Serialization::ColumnNotSerializableError) do
+ new_klass.new
+ end
+ end
end
class PostgresqlJSONTest < ActiveRecord::PostgreSQLTestCase