Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor adapters to implement support for array serialization #684

Merged
merged 1 commit into from
Oct 15, 2014
Merged
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
8 changes: 1 addition & 7 deletions lib/active_model/serializer/adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,7 @@ def serializable_hash(options = {})
end

def to_json(options = {})
result = serializable_hash(options)

if root = options.fetch(:root, serializer.json_key)
result = { root => result }
end

result.to_json
serializable_hash(options).to_json
Copy link
Member Author

Choose a reason for hiding this comment

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

root semantics must be moved outside of the base adapter since the adapters can handle it in different ways, then I've moved it to serialized_hash

For example in JSON-API document top-level document may also have other members (meta, links, linked)

end
end
end
Expand Down
24 changes: 16 additions & 8 deletions lib/active_model/serializer/adapter/json.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,26 @@ class Serializer
class Adapter
class Json < Adapter
def serializable_hash(options = {})
@hash = serializer.attributes(options)
if serializer.respond_to?(:each)
@result = serializer.map{|s| self.class.new(s).serializable_hash }
else
@result = serializer.attributes(options)

serializer.each_association do |name, association, options|
if association.respond_to?(:each)
array_serializer = association
@hash[name] = array_serializer.map { |item| item.attributes(options) }
else
@hash[name] = association.attributes(options)
serializer.each_association do |name, association, opts|
if association.respond_to?(:each)
array_serializer = association
@result[name] = array_serializer.map { |item| item.attributes(opts) }
else
@result[name] = association.attributes(options)
end
end
end

@hash
if root = options.fetch(:root, serializer.json_key)
@result = { root => @result }
end

@result
end
end
end
Expand Down
41 changes: 24 additions & 17 deletions lib/active_model/serializer/adapter/json_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,38 @@ class Adapter
class JsonApi < Adapter
def initialize(serializer, options = {})
super
serializer.root ||= true
serializer.root = true
end

def serializable_hash(opts = {})
@hash = serializer.attributes

serializer.each_association do |name, association, options|
@hash[:links] ||= {}
unless options[:embed] == :ids
@hash[:linked] ||= {}
end

if association.respond_to?(:each)
add_links(name, association, options)
else
add_link(name, association, options)
def serializable_hash(options = {})
@root = (options[:root] || serializer.json_key).to_s.pluralize.to_sym
@hash = {}

if serializer.respond_to?(:each)
@hash[@root] = serializer.map{|s| self.class.new(s).serializable_hash[@root] }
else
@hash[@root] = serializer.attributes

serializer.each_association do |name, association, opts|
@hash[@root][:links] ||= {}
unless options[:embed] == :ids
@hash[:linked] ||= {}
end

if association.respond_to?(:each)
add_links(name, association, opts)
else
add_link(name, association, opts)
end
end
end

@hash
end

def add_links(name, serializers, options)
@hash[:links][name] ||= []
@hash[:links][name] += serializers.map(&:id)
@hash[@root][:links][name] ||= []
@hash[@root][:links][name] += serializers.map(&:id)

unless options[:embed] == :ids
@hash[:linked][name] ||= []
Expand All @@ -37,7 +44,7 @@ def add_links(name, serializers, options)
end

def add_link(name, serializer, options)
@hash[:links][name] = serializer.id
@hash[@root][:links][name] = serializer.id

unless options[:embed] == :ids
plural_name = name.to_s.pluralize.to_sym
Expand Down
8 changes: 8 additions & 0 deletions lib/active_model/serializer/array_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ def initialize(objects, options = {})
serializer_class.new(object)
end
end

def json_key
@objects.first.json_key if @objects.first
end

def root=(root)
@objects.first.root = root if @objects.first
end
end
end
end
28 changes: 27 additions & 1 deletion test/action_controller/serialization_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ def render_using_default_adapter_root
ensure
ActiveModel::Serializer.config.adapter = old_adapter
end

def render_array_using_implicit_serializer
array = [
Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' }),
Profile.new({ name: 'Name 2', description: 'Description 2', comments: 'Comments 2' })
]
render json: array
end
end

tests MyController
Expand All @@ -46,7 +54,25 @@ def test_render_using_default_root
get :render_using_default_adapter_root

assert_equal 'application/json', @response.content_type
assert_equal '{"profile":{"name":"Name 1","description":"Description 1"}}', @response.body
assert_equal '{"profiles":{"name":"Name 1","description":"Description 1"}}', @response.body
end

def test_render_array_using_implicit_serializer
get :render_array_using_implicit_serializer
assert_equal 'application/json', @response.content_type

expected = [
{
name: 'Name 1',
description: 'Description 1',
},
{
name: 'Name 2',
description: 'Description 2',
}
]

assert_equal expected.to_json, @response.body
end
end
end
Expand Down
28 changes: 28 additions & 0 deletions test/adapter/json/collection_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require 'test_helper'

module ActiveModel
class Serializer
class Adapter
class Json
class Collection < Minitest::Test
def setup
@first_post = Post.new(id: 1, title: 'Hello!!', body: 'Hello, world!!')
@second_post = Post.new(id: 2, title: 'New Post', body: 'Body')
@first_post.comments = []
@second_post.comments = []

@serializer = ArraySerializer.new([@first_post, @second_post])
@adapter = ActiveModel::Serializer::Adapter::Json.new(@serializer)
end

def test_include_multiple_posts
assert_equal([
{title: "Hello!!", body: "Hello, world!!", id: 1, comments: []},
{title: "New Post", body: "Body", id: 2, comments: []}
], @adapter.serializable_hash)
end
end
end
end
end
end
2 changes: 1 addition & 1 deletion test/adapter/json_api/belongs_to_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def setup
end

def test_includes_post_id
assert_equal(42, @adapter.serializable_hash[:links][:post])
assert_equal(42, @adapter.serializable_hash[:comments][:links][:post])
end

def test_includes_linked_post
Expand Down
28 changes: 28 additions & 0 deletions test/adapter/json_api/collection_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require 'test_helper'

module ActiveModel
class Serializer
class Adapter
class JsonApi
class Collection < Minitest::Test
def setup
@first_post = Post.new(id: 1, title: 'Hello!!', body: 'Hello, world!!')
@second_post = Post.new(id: 2, title: 'New Post', body: 'Body')
@first_post.comments = []
@second_post.comments = []

@serializer = ArraySerializer.new([@first_post, @second_post])
@adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer)
end

def test_include_multiple_posts
assert_equal([
{title: "Hello!!", body: "Hello, world!!", id: 1, links: {comments: []}},
{title: "New Post", body: "Body", id: 2, links: {comments: []}}
], @adapter.serializable_hash[:posts])
end
end
end
end
end
end
2 changes: 1 addition & 1 deletion test/adapter/json_api/has_many_embed_ids.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def setup
end

def test_includes_comment_ids
assert_equal([1, 2], @adapter.serializable_hash[:links][:posts])
assert_equal([1, 2], @adapter.serializable_hash[:authors][:links][:posts])
end

def test_no_includes_linked_comments
Expand Down
2 changes: 1 addition & 1 deletion test/adapter/json_api/has_many_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def setup
end

def test_includes_comment_ids
assert_equal([1, 2], @adapter.serializable_hash[:links][:comments])
assert_equal([1, 2], @adapter.serializable_hash[:posts][:links][:comments])
end

def test_includes_linked_comments
Expand Down
4 changes: 2 additions & 2 deletions test/array_serializer_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ class Serializer
class ArraySerializerTest < Minitest::Test
def setup
@comment = Comment.new
@post= Post.new
@post = Post.new
@serializer = ArraySerializer.new([@comment, @post])
end

def test_respond_to_each
assert_respond_to @serializer, :each
end

def test_each_object_should_be_serializer_with_appropriate_serializer
def test_each_object_should_be_serialized_with_appropriate_serializer
serializers = @serializer.to_a

assert_kind_of CommentSerializer, serializers.first
Expand Down