Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion lib/active_model/serializable_resource.rb
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
4 changes: 0 additions & 4 deletions lib/active_model/serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
4 changes: 0 additions & 4 deletions lib/active_model/serializer/adapter/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 18 additions & 0 deletions lib/active_model/serializer/adapter/json.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

vs.

   def json_key
-      root || object.class.model_name.to_s.underscore
-    end

and

-      def json_key
-        key = root || serializers.first.try(:json_key) || object.try(:name).try(:underscore)
-        key.try(:pluralize)
-      end

?

Shouldn't this just be using the Serializer type or am I tired?
I'm not convinced

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Highly possible that the serializer's type is the right thing to use here. Main point of this PR was that an option that is specific to the Json adapter should not clutter the Serializer and Adapter::Base classes with lots of overcomplicated code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that type is nil unless explicitly specified though.

end
end
end
Expand Down
8 changes: 1 addition & 7 deletions lib/active_model/serializer/array_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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) &&
Expand Down
4 changes: 2 additions & 2 deletions test/action_controller/serialization_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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' }] }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this raises a huge red flag for me. Why is this changing?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it should not have been there in the first place. Modifying explicitly supplied options is such an antipattern. I could move this change to an other PR though.

assert_equal 'application/json', @response.content_type
assert_equal expected.to_json, @response.body
end
Expand All @@ -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
Expand Down
78 changes: 78 additions & 0 deletions test/adapter/json/array_test.rb
Original file line number Diff line number Diff line change
@@ -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
27 changes: 27 additions & 0 deletions test/adapter/json/root_test.rb
Original file line number Diff line number Diff line change
@@ -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
17 changes: 13 additions & 4 deletions test/adapter/json_api/belongs_to_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use the serializable helper to for less words, if you want

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the helper globally available? I think it should be. If so, I'll update these tests.

@comment,
adapter: :json_api,
include: [:post])
.serializable_hash
expected = [{
id: '42',
type: 'posts',
Expand All @@ -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',
Expand All @@ -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
Expand Down
48 changes: 0 additions & 48 deletions test/array_serializer_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
21 changes: 0 additions & 21 deletions test/serializers/root_test.rb

This file was deleted.