diff --git a/CHANGELOG.md b/CHANGELOG.md index ea0d772e5..1eab9a8a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ Fixes: - [#1214](https://github.com/rails-api/active_model_serializers/pull/1214) retrieve the key from the reflection options when building associations (@NullVoxPopuli, @hut8) Misc: +- [#1234](https://github.com/rails-api/active_model_serializers/pull/1234) root option no longer handled at serializer level (@beauby) - [#1233](https://github.com/rails-api/active_model_serializers/pull/1233) Top-level meta and meta_key options no longer handled at serializer level (@beauby) - [#1232](https://github.com/rails-api/active_model_serializers/pull/1232) fields option no longer handled at serializer level (@beauby) - [#1178](https://github.com/rails-api/active_model_serializers/pull/1178) env CAPTURE_STDERR=false lets devs see hard failures (@bf4) diff --git a/lib/active_model/serializable_resource.rb b/lib/active_model/serializable_resource.rb index da1a772a8..81c0ea1d6 100644 --- a/lib/active_model/serializable_resource.rb +++ b/lib/active_model/serializable_resource.rb @@ -1,7 +1,7 @@ require 'set' module ActiveModel class SerializableResource - ADAPTER_OPTION_KEYS = Set.new([:include, :fields, :adapter, :meta, :meta_key, :links]) + ADAPTER_OPTION_KEYS = Set.new([:include, :fields, :adapter, :meta, :meta_key, :links, :root]) # Primary interface to composing a resource with a serializer and adapter. # @return the serializable_resource, ready for #as_json/#to_json/#serializable_hash. diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 27068b621..40d7d2493 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -164,10 +164,6 @@ def initialize(object, options = {}) end end - def json_key - root || object.class.model_name.to_s.underscore - end - def attributes attributes = self.class._attributes.dup diff --git a/lib/active_model/serializer/adapter/base.rb b/lib/active_model/serializer/adapter/base.rb index fc06848a9..58410a58e 100644 --- a/lib/active_model/serializer/adapter/base.rb +++ b/lib/active_model/serializer/adapter/base.rb @@ -44,10 +44,6 @@ def meta_key instance_options.fetch(:meta_key, 'meta'.freeze) end - def root - serializer.json_key.to_sym if serializer.json_key - end - def include_meta(json) json[meta_key] = meta if meta json diff --git a/lib/active_model/serializer/adapter/json.rb b/lib/active_model/serializer/adapter/json.rb index ab81f5710..021dbf93b 100644 --- a/lib/active_model/serializer/adapter/json.rb +++ b/lib/active_model/serializer/adapter/json.rb @@ -15,6 +15,24 @@ def serializable_hash(options = nil) def fragment_cache(cached_hash, non_cached_hash) ActiveModel::Serializer::Adapter::Json::FragmentCache.new.fragment_cache(cached_hash, non_cached_hash) end + + def root + root = instance_options.fetch(:root) do + if serializer.respond_to?(:each) + key = + if serializer.first + serializer.first.object.class.model_name + else + serializer.object.try(:name) + end + key.to_s.pluralize + else + serializer.object.class.model_name.to_s + end + end + + root.to_s.underscore.to_sym + end end end end diff --git a/lib/active_model/serializer/array_serializer.rb b/lib/active_model/serializer/array_serializer.rb index f9c91ea9e..114e851f5 100644 --- a/lib/active_model/serializer/array_serializer.rb +++ b/lib/active_model/serializer/array_serializer.rb @@ -5,10 +5,9 @@ class ArraySerializer include Enumerable delegate :each, to: :@serializers - attr_reader :object, :root + attr_reader :object def initialize(resources, options = {}) - @root = options[:root] @object = resources @serializers = resources.map do |resource| serializer_context_class = options.fetch(:serializer_context_class, ActiveModel::Serializer) @@ -22,11 +21,6 @@ def initialize(resources, options = {}) end end - def json_key - key = root || serializers.first.try(:json_key) || object.try(:name).try(:underscore) - key.try(:pluralize) - end - def paginated? object.respond_to?(:current_page) && object.respond_to?(:total_pages) && diff --git a/test/action_controller/serialization_test.rb b/test/action_controller/serialization_test.rb index e9288d564..e357d9ff4 100644 --- a/test/action_controller/serialization_test.rb +++ b/test/action_controller/serialization_test.rb @@ -171,7 +171,7 @@ def test_render_array_using_custom_root with_adapter :json do get :render_array_using_custom_root end - expected = { custom_roots: [{ name: 'Name 1', description: 'Description 1' }] } + expected = { custom_root: [{ name: 'Name 1', description: 'Description 1' }] } assert_equal 'application/json', @response.content_type assert_equal expected.to_json, @response.body end @@ -181,7 +181,7 @@ def test_render_array_that_is_empty_using_custom_root get :render_array_that_is_empty_using_custom_root end - expected = { custom_roots: [] } + expected = { custom_root: [] } assert_equal 'application/json', @response.content_type assert_equal expected.to_json, @response.body end diff --git a/test/adapter/json/array_test.rb b/test/adapter/json/array_test.rb new file mode 100644 index 000000000..9212d9f4b --- /dev/null +++ b/test/adapter/json/array_test.rb @@ -0,0 +1,78 @@ +require 'test_helper' + +module ActiveModel + class Serializer + module Adapter + class Json + class ArrayTest < Minitest::Test + def setup + @comment = Comment.new + @post = Post.new + @resource = build_named_collection @comment, @post + end + + def build_named_collection(*resource) + resource.define_singleton_method(:name) { 'MeResource' } + resource + end + + def test_root_default + serializer = ArraySerializer.new([@comment, @post]) + adapter = Json.new(serializer) + assert_equal(:comments, adapter.send(:root)) + end + + def test_root + serializer = ArraySerializer.new([@comment, @post]) + adapter = Json.new(serializer, root: 'custom_root') + assert_equal(:custom_root, adapter.send(:root)) + end + + def test_root_with_no_serializers + serializer = ArraySerializer.new([]) + adapter = Json.new(serializer, root: 'custom_root') + assert_equal(:custom_root, adapter.send(:root)) + end + + def test_root_with_resource_with_name_and_serializers + serializer = ArraySerializer.new(@resource) + adapter = Json.new(serializer) + assert_equal(:comments, adapter.send(:root)) + end + + def test_root_with_resource_with_name_and_no_serializers + serializer = ArraySerializer.new(build_named_collection) + adapter = Json.new(serializer) + assert_equal(:me_resources, adapter.send(:root)) + end + + def test_root_with_resource_with_nil_name_and_no_serializers + resource = [] + resource.define_singleton_method(:name) { nil } + serializer = ArraySerializer.new(resource) + adapter = Json.new(serializer) + assert_equal(:'', adapter.send(:root)) + end + + def test_root_with_resource_without_name_and_no_serializers + serializer = ArraySerializer.new([]) + adapter = Json.new(serializer) + assert_equal(:'', adapter.send(:root)) + end + + def test_root_with_explicit_root + serializer = ArraySerializer.new(@resource) + adapter = Json.new(serializer, root: 'custom_root') + assert_equal(:custom_root, adapter.send(:root)) + end + + def test_root_with_explicit_root_and_no_serializers + serializer = ArraySerializer.new(build_named_collection) + adapter = Json.new(serializer, root: 'custom_root') + assert_equal(:custom_root, adapter.send(:root)) + end + end + end + end + end +end diff --git a/test/adapter/json/root_test.rb b/test/adapter/json/root_test.rb new file mode 100644 index 000000000..f690fd72e --- /dev/null +++ b/test/adapter/json/root_test.rb @@ -0,0 +1,27 @@ +require 'test_helper' + +module ActiveModel + class Serializer + module Adapter + class Json + class RootTest < Minitest::Test + def setup + @virtual_value = VirtualValue.new(id: 1) + end + + def test_overwrite_root + serializer = VirtualValueSerializer.new(@virtual_value) + adapter = Json.new(serializer, root: 'smth') + assert_equal(:smth, adapter.send(:root)) + end + + def test_underscore_in_root + serializer = VirtualValueSerializer.new(@virtual_value) + adapter = Json.new(serializer) + assert_equal(:virtual_value, adapter.send(:root)) + end + end + end + end + end +end diff --git a/test/adapter/json_api/belongs_to_test.rb b/test/adapter/json_api/belongs_to_test.rb index acf98f4fa..0406a20d4 100644 --- a/test/adapter/json_api/belongs_to_test.rb +++ b/test/adapter/json_api/belongs_to_test.rb @@ -38,7 +38,11 @@ def test_includes_post_id end def test_includes_linked_post - @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: [:post]) + actual = ActiveModel::SerializableResource.new( + @comment, + adapter: :json_api, + include: [:post]) + .serializable_hash expected = [{ id: '42', type: 'posts', @@ -52,11 +56,16 @@ def test_includes_linked_post author: { data: { type: 'authors', id: '1' } } } }] - assert_equal expected, @adapter.serializable_hash[:included] + assert_equal expected, actual[:included] end def test_limiting_linked_post_fields - @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer, include: [:post], fields: { post: [:title] }) + actual = ActiveModel::SerializableResource.new( + @comment, + adapter: :json_api, + include: [:post], + fields: { post: [:title] }) + .serializable_hash expected = [{ id: '42', type: 'posts', @@ -69,7 +78,7 @@ def test_limiting_linked_post_fields author: { data: { type: 'authors', id: '1' } } } }] - assert_equal expected, @adapter.serializable_hash[:included] + assert_equal expected, actual[:included] end def test_include_nil_author diff --git a/test/array_serializer_test.rb b/test/array_serializer_test.rb index 3141f7131..202100d8b 100644 --- a/test/array_serializer_test.rb +++ b/test/array_serializer_test.rb @@ -40,54 +40,6 @@ def test_serializer_option_not_passed_to_each_serializer refute serializers.first.custom_options.key?(:serializer) end - - def test_root_default - @serializer = ArraySerializer.new([@comment, @post]) - assert_equal @serializer.root, nil - end - - def test_root - expected = 'custom_root' - @serializer = ArraySerializer.new([@comment, @post], root: expected) - assert_equal @serializer.root, expected - end - - def test_root_with_no_serializers - expected = 'custom_root' - @serializer = ArraySerializer.new([], root: expected) - assert_equal @serializer.root, expected - end - - def test_json_key - assert_equal @serializer.json_key, 'comments' - end - - def test_json_key_with_resource_with_name_and_no_serializers - serializer = ArraySerializer.new(build_named_collection) - assert_equal serializer.json_key, 'me_resources' - end - - def test_json_key_with_resource_with_nil_name_and_no_serializers - resource = [] - resource.define_singleton_method(:name) { nil } - serializer = ArraySerializer.new(resource) - assert_equal serializer.json_key, nil - end - - def test_json_key_with_resource_without_name_and_no_serializers - serializer = ArraySerializer.new([]) - assert_equal serializer.json_key, nil - end - - def test_json_key_with_root - serializer = ArraySerializer.new(@resource, root: 'custom_root') - assert_equal serializer.json_key, 'custom_roots' - end - - def test_json_key_with_root_and_no_serializers - serializer = ArraySerializer.new(build_named_collection, root: 'custom_root') - assert_equal serializer.json_key, 'custom_roots' - end end end end diff --git a/test/serializers/root_test.rb b/test/serializers/root_test.rb deleted file mode 100644 index 03e6ca20f..000000000 --- a/test/serializers/root_test.rb +++ /dev/null @@ -1,21 +0,0 @@ -require 'test_helper' - -module ActiveModel - class Serializer - class RootTest < Minitest::Test - def setup - @virtual_value = VirtualValue.new(id: 1) - end - - def test_overwrite_root - serializer = VirtualValueSerializer.new(@virtual_value, { root: 'smth' }) - assert_equal('smth', serializer.json_key) - end - - def test_underscore_in_root - serializer = VirtualValueSerializer.new(@virtual_value) - assert_equal('virtual_value', serializer.json_key) - end - end - end -end