Skip to content

Commit

Permalink
Do not let use serialize on native JSON/array column
Browse files Browse the repository at this point in the history
  • Loading branch information
kirs committed Aug 4, 2017
1 parent 904f1a8 commit a0751d2
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 0 deletions.
24 changes: 24 additions & 0 deletions activerecord/lib/active_record/attribute_methods/serialization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ module AttributeMethods
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
Expand Down Expand Up @@ -60,9 +70,23 @@ def serialize(attr_name, class_name_or_coder = Object)
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
Expand Down
9 changes: 9 additions & 0 deletions activerecord/test/cases/adapters/postgresql/array_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ def test_column
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
Expand Down
9 changes: 9 additions & 0 deletions activerecord/test/cases/adapters/postgresql/json_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,15 @@ def test_deserialize_with_array
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
Expand Down

0 comments on commit a0751d2

Please sign in to comment.