diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 3f21e1f3d..950277a95 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -18,7 +18,7 @@ # reified when subclassed to decorate a resource. module ActiveModel class Serializer - SERIALIZABLE_HASH_VALID_KEYS = [:only, :except, :methods, :include].freeze + SERIALIZABLE_HASH_VALID_KEYS = [:only, :except, :methods, :include, :root].freeze extend ActiveSupport::Autoload autoload :Adapter autoload :Null diff --git a/lib/active_model_serializers/adapter/attributes.rb b/lib/active_model_serializers/adapter/attributes.rb index 38446d846..95189233a 100644 --- a/lib/active_model_serializers/adapter/attributes.rb +++ b/lib/active_model_serializers/adapter/attributes.rb @@ -8,7 +8,7 @@ def initialize(serializer, options = {}) end def serializable_hash(options = nil) - options = super + options = serialization_options(options) if serializer.respond_to?(:each) serializable_hash_for_collection(options) diff --git a/lib/active_model_serializers/adapter/base.rb b/lib/active_model_serializers/adapter/base.rb index 04d30ca8e..a73aa6d7b 100644 --- a/lib/active_model_serializers/adapter/base.rb +++ b/lib/active_model_serializers/adapter/base.rb @@ -19,8 +19,10 @@ def cached_name @cached_name ||= self.class.name.demodulize.underscore end - def serializable_hash(options = nil) - (options ||= {}).slice(*ActiveModel::Serializer::SERIALIZABLE_HASH_VALID_KEYS) # rubocop:disable Lint/UselessAssignment + # Subclasses that implement this method must first call + # options = serialization_options(options) + def serializable_hash(_options = nil) + fail NotImplementedError, 'This is an abstract method. Should be implemented at the concrete adapter.' end def as_json(options = nil) @@ -41,6 +43,10 @@ def cache_check(serializer) private + def serialization_options(options) + (options ||= {}).slice(*ActiveModel::Serializer::SERIALIZABLE_HASH_VALID_KEYS) # rubocop:disable Lint/UselessAssignment + end + def meta instance_options.fetch(:meta, nil) end diff --git a/lib/active_model_serializers/adapter/json.rb b/lib/active_model_serializers/adapter/json.rb index 486e1c57b..69960212e 100644 --- a/lib/active_model_serializers/adapter/json.rb +++ b/lib/active_model_serializers/adapter/json.rb @@ -2,7 +2,7 @@ module ActiveModelSerializers module Adapter class Json < Base def serializable_hash(options = nil) - options = super + options = serialization_options(options) serialized_hash = { root => Attributes.new(serializer, instance_options).serializable_hash(options) } transform_key_casing!(serialized_hash) end diff --git a/test/adapter_test.rb b/test/adapter_test.rb index 01dddc2f2..b3821c467 100644 --- a/test/adapter_test.rb +++ b/test/adapter_test.rb @@ -8,10 +8,21 @@ def setup @adapter = ActiveModelSerializers::Adapter::Base.new(@serializer) end - def test_serializable_ensures_options_is_a_hash - assert_equal({ only: [:name] }, @adapter.serializable_hash(only: [:name])) - assert_equal({}, @adapter.serializable_hash(nil)) - assert_equal({}, @adapter.serializable_hash({})) + def test_serializable_hash_is_abstract_method + assert_raises(NotImplementedError) do + @adapter.serializable_hash(only: [:name]) + end + end + + def test_serialization_options_ensures_option_is_a_hash + adapter = Class.new(ActiveModelSerializers::Adapter::Base) do + def serializable_hash(options = nil) + serialization_options(options) + end + end.new(@serializer) + assert_equal({ only: [:name] }, adapter.serializable_hash(only: [:name])) + assert_equal({}, adapter.serializable_hash(nil)) + assert_equal({}, adapter.serializable_hash({})) end def test_serializer