From 1db96ec7a9fd0070be859aca5a5cc610bb832d51 Mon Sep 17 00:00:00 2001 From: Arne Brasseur Date: Mon, 11 Nov 2013 14:30:34 +0100 Subject: [PATCH] When using embed: :ids ; embed_in_root: true, and serializing multiple objects, only the associated objects of the last object in the collection will actually show up in the serialized data. For example, if you serialize a collection of two posts, each containing one or more comments, only the comments of the last post show up. The reason is a Hash#merge wich overwrites the array rather than appending to it. This commit fixes this by merging the collection arrays, rather than the top-level hashes. --- lib/active_model/array_serializer.rb | 5 ++- test/fixtures/poro.rb | 2 + .../array_serializer/embed_in_root_test.rb | 45 +++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 test/unit/active_model/array_serializer/embed_in_root_test.rb diff --git a/lib/active_model/array_serializer.rb b/lib/active_model/array_serializer.rb index ce73ece1..ccfad26f 100644 --- a/lib/active_model/array_serializer.rb +++ b/lib/active_model/array_serializer.rb @@ -44,7 +44,10 @@ module ActiveModel def embedded_in_root_associations @object.each_with_object({}) do |item, hash| - hash.merge!(serializer_for(item).embedded_in_root_associations) + serializer_for(item).embedded_in_root_associations.each_pair do |type, objects| + hash[type] = hash.fetch(type, []).concat(objects) + hash[type].uniq! + end end end end diff --git a/test/fixtures/poro.rb b/test/fixtures/poro.rb index a43954b5..66ab74ee 100644 --- a/test/fixtures/poro.rb +++ b/test/fixtures/poro.rb @@ -26,6 +26,8 @@ class Profile < Model end class Post < Model + attr_writer :comments + def comments @comments ||= [Comment.new(content: 'C1'), Comment.new(content: 'C2')] diff --git a/test/unit/active_model/array_serializer/embed_in_root_test.rb b/test/unit/active_model/array_serializer/embed_in_root_test.rb new file mode 100644 index 00000000..2ae5b616 --- /dev/null +++ b/test/unit/active_model/array_serializer/embed_in_root_test.rb @@ -0,0 +1,45 @@ +require 'test_helper' + +module ActiveModel + class ArraySerializer + class EmbedInRootTest < ActiveModel::TestCase + def setup + @association = PostSerializer._associations[:comments] + @old_association = @association.dup + + @post1 = Post.new({ title: 'Title 1', body: 'Body 1', date: '1/1/2000' }) + @post2 = Post.new({ title: 'Title 2', body: 'Body 2', date: '1/1/2000' }) + + @post2.comments = [ + Comment.new(content: 'C3'), + Comment.new(content: 'C4') + ] + + @serializer = ArraySerializer.new([@post1, @post2], root: :posts) + end + + def teardown + PostSerializer._associations[:comments] = @old_association + end + + def test_associated_objects_of_multiple_instances_embedded_in_root + @association.embed = :ids + @association.embed_in_root = true + + assert_equal({ + posts: [ + {title: "Title 1", body: "Body 1", "comment_ids" => @post1.comments.map(&:object_id) }, + {title: "Title 2", body: "Body 2", "comment_ids" => @post2.comments.map(&:object_id) } + ], + comments: [ + {content: "C1"}, + {content: "C2"}, + {content: "C3"}, + {content: "C4"} + ] + }, @serializer.as_json) + end + + end + end +end