diff --git a/lib/active_model/serializable.rb b/lib/active_model/serializable.rb index 944cb0aa..897ea13f 100644 --- a/lib/active_model/serializable.rb +++ b/lib/active_model/serializable.rb @@ -3,11 +3,19 @@ module ActiveModel def as_json(options={}) if root = options[:root] || self.root hash = { root.to_s => serializable_object } - hash[meta_key.to_s] = meta if meta + hash.merge!(serializable_data) hash else serializable_object end end + + def serializable_data + if respond_to?(:meta) && meta + { meta_key.to_s => meta } + else + {} + end + end end end diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 7fa1a31f..a7af3235 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -70,15 +70,20 @@ module ActiveModel def initialize(object, options={}) @object = object @scope = options[:scope] - @root = options[:root] || self.class._root - @root = self.class.root_name if @root == true + self.root = options[:root] @meta_key = options[:meta_key] || :meta @meta = options[@meta_key] end - attr_accessor :object, :scope, :root, :meta_key, :meta + attr_accessor :object, :scope, :meta_key, :meta + attr_reader :root alias read_attribute_for_serialization send + def root=(root) + @root = root || self.class._root + @root = self.class.root_name if auto_assign_root? + end + def attributes self.class._attributes.each_with_object({}) do |name, hash| hash[name] = send(name) @@ -89,8 +94,19 @@ module ActiveModel self.class._associations.each_with_object({}) do |association, hash| if association.embed_ids? hash[association.key] = serialize_ids association + elsif association.embed_objects? + hash[association.embedded_key] = serialize association end - if association.embed_objects? + end + end + + def serializable_data + embedded_in_root_associations.merge!(super) + end + + def embedded_in_root_associations + self.class._associations.each_with_object({}) do |association, hash| + if association.embed_in_root? hash[association.embedded_key] = serialize association end end @@ -120,5 +136,11 @@ module ActiveModel hash.merge! associations end alias serializable_object serializable_hash + + private + + def auto_assign_root? + @root == true || !@root && self.class._associations.any? { |a| a.embed_in_root? } + end end end diff --git a/lib/active_model/serializer/associations.rb b/lib/active_model/serializer/associations.rb index 369b2eff..91d473fc 100644 --- a/lib/active_model/serializer/associations.rb +++ b/lib/active_model/serializer/associations.rb @@ -7,20 +7,20 @@ module ActiveModel @name = name @options = options - self.embed = options[:embed] - @embed_key = options[:embed_key] || :id - @include = options[:include] - @key = options[:key] - @embedded_key = options[:root] + self.embed = options[:embed] + @embed_in_root = @embed_ids && options[:include] + @embed_key = options[:embed_key] || :id + @key = options[:key] + @embedded_key = options[:root] self.serializer_class = @options[:serializer] end - attr_reader :name, :embed_ids, :embed_objects, :embed_key, :serializer_class, :options - attr_accessor :include, :key, :embedded_key + attr_reader :name, :embed_ids, :embed_objects, :serializer_class + attr_accessor :embed_in_root, :embed_key, :key, :embedded_key, :options alias embed_ids? embed_ids alias embed_objects? embed_objects - alias include? include + alias embed_in_root? embed_in_root def serializer_class=(serializer) @serializer_class = serializer.is_a?(String) ? serializer.constantize : serializer @@ -31,10 +31,6 @@ module ActiveModel @embed_objects = embed == :object || embed == :objects end - def embed_objects? - @embed_objects || @embed_ids && @include - end - def build_serializer(object) @serializer_class ||= Serializer.serializer_for(object) diff --git a/test/unit/active_model/serializer/has_many_test.rb b/test/unit/active_model/serializer/has_many_test.rb index efab83e5..a4837a5b 100644 --- a/test/unit/active_model/serializer/has_many_test.rb +++ b/test/unit/active_model/serializer/has_many_test.rb @@ -4,11 +4,15 @@ module ActiveModel class Serializer class HasManyTest < ActiveModel::TestCase def setup + @association = PostSerializer._associations[0] + @old_association = @association.dup + @association.embed = :ids @post = Post.new({ title: 'Title 1', body: 'Body 1', date: '1/1/2000' }) @post_serializer = PostSerializer.new(@post) - @association = PostSerializer._associations[0] - @association.include = false - @association.embed = :ids + end + + def teardown + PostSerializer._associations[0] = @old_association end def test_associations_definition @@ -30,13 +34,10 @@ module ActiveModel end def test_associations_embedding_ids_serialization_using_serializable_hash_and_key_from_options - old_key = @association.key @association.key = 'key' assert_equal({ 'title' => 'Title 1', 'body' => 'Body 1', 'key' => @post.comments.map { |c| c.object_id } }, @post_serializer.serializable_hash) - ensure - @association.key = old_key end def test_associations_embedding_objects_serialization_using_serializable_hash @@ -55,32 +56,32 @@ module ActiveModel def test_associations_embedding_objects_serialization_using_serializable_hash_and_root_from_options @association.embed = :objects - old_embedded_key = @association.embedded_key @association.embedded_key = 'root' assert_equal({ 'title' => 'Title 1', 'body' => 'Body 1', 'root' => [{ 'content' => 'C1' }, { 'content' => 'C2' }] }, @post_serializer.serializable_hash) - ensure - @association.embedded_key = old_embedded_key end def test_associations_embedding_ids_including_objects_serialization_using_serializable_hash - @association.include = true + @association.embed_in_root = true + @post_serializer.root = nil assert_equal({ - 'title' => 'Title 1', 'body' => 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id }, 'comments' => [{ 'content' => 'C1' }, { 'content' => 'C2' }] + 'title' => 'Title 1', 'body' => 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id } }, @post_serializer.serializable_hash) end def test_associations_embedding_ids_including_objects_serialization_using_as_json - @association.include = true + @association.embed_in_root = true + @post_serializer.root = nil assert_equal({ - 'title' => 'Title 1', 'body' => 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id }, 'comments' => [{ 'content' => 'C1' }, { 'content' => 'C2' }] + 'post' => { 'title' => 'Title 1', 'body' => 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id } }, + 'comments' => [{ 'content' => 'C1' }, { 'content' => 'C2' }] }, @post_serializer.as_json) end def test_associations_using_a_given_serializer - @old_serializer = @association.serializer_class - @association.include = true + @association.embed_in_root = true + @post_serializer.root = nil @association.serializer_class = Class.new(ActiveModel::Serializer) do def content 'fake' @@ -90,10 +91,9 @@ module ActiveModel end assert_equal({ - 'title' => 'Title 1', 'body' => 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id }, 'comments' => [{ 'content' => 'fake' }, { 'content' => 'fake' }] + 'post' => { 'title' => 'Title 1', 'body' => 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id } }, + 'comments' => [{ 'content' => 'fake' }, { 'content' => 'fake' }] }, @post_serializer.as_json) - ensure - @association.serializer_class = @old_serializer end end end diff --git a/test/unit/active_model/serializer/has_one_test.rb b/test/unit/active_model/serializer/has_one_test.rb index 2a34426b..f7028548 100644 --- a/test/unit/active_model/serializer/has_one_test.rb +++ b/test/unit/active_model/serializer/has_one_test.rb @@ -4,11 +4,15 @@ module ActiveModel class Serializer class HasOneTest < ActiveModel::TestCase def setup + @association = UserSerializer._associations[0] + @old_association = @association.dup + @association.embed = :ids @user = User.new({ name: 'Name 1', email: 'mail@server.com', gender: 'M' }) @user_serializer = UserSerializer.new(@user) - @association = UserSerializer._associations[0] - @association.include = false - @association.embed = :ids + end + + def teardown + UserSerializer._associations[0] = @old_association end def test_associations_definition @@ -30,13 +34,10 @@ module ActiveModel end def test_associations_embedding_ids_serialization_using_serializable_hash_and_key_from_options - old_key = @association.key @association.key = 'key' assert_equal({ 'name' => 'Name 1', 'email' => 'mail@server.com', 'key' => @user.profile.object_id }, @user_serializer.serializable_hash) - ensure - @association.key = old_key end def test_associations_embedding_objects_serialization_using_serializable_hash @@ -55,32 +56,32 @@ module ActiveModel def test_associations_embedding_objects_serialization_using_serializable_hash_and_root_from_options @association.embed = :objects - old_embedded_key = @association.embedded_key @association.embedded_key = 'root' assert_equal({ 'name' => 'Name 1', 'email' => 'mail@server.com', 'root' => [{ 'name' => 'N1', 'description' => 'D1' }] }, @user_serializer.serializable_hash) - ensure - @association.embedded_key = old_embedded_key end def test_associations_embedding_ids_including_objects_serialization_using_serializable_hash - @association.include = true + @association.embed_in_root = true + @user_serializer.root = nil assert_equal({ - 'name' => 'Name 1', 'email' => 'mail@server.com', 'profile_id' => @user.profile.object_id, 'profiles' => [{ 'name' => 'N1', 'description' => 'D1' }] + 'name' => 'Name 1', 'email' => 'mail@server.com', 'profile_id' => @user.profile.object_id }, @user_serializer.serializable_hash) end def test_associations_embedding_ids_including_objects_serialization_using_as_json - @association.include = true + @association.embed_in_root = true + @user_serializer.root = nil assert_equal({ - 'name' => 'Name 1', 'email' => 'mail@server.com', 'profile_id' => @user.profile.object_id, 'profiles' => [{ 'name' => 'N1', 'description' => 'D1' }] + 'user' => { 'name' => 'Name 1', 'email' => 'mail@server.com', 'profile_id' => @user.profile.object_id }, + 'profiles' => [{ 'name' => 'N1', 'description' => 'D1' }] }, @user_serializer.as_json) end def test_associations_using_a_given_serializer - @old_serializer = @association.serializer_class - @association.include = true + @association.embed_in_root = true + @user_serializer.root = nil @association.serializer_class = Class.new(ActiveModel::Serializer) do def name 'fake' @@ -90,10 +91,9 @@ module ActiveModel end assert_equal({ - 'name' => 'Name 1', 'email' => 'mail@server.com', 'profile_id' => @user.profile.object_id, 'profiles' => [{ 'name' => 'fake' }] + 'user' => { 'name' => 'Name 1', 'email' => 'mail@server.com', 'profile_id' => @user.profile.object_id }, + 'profiles' => [{ 'name' => 'fake' }] }, @user_serializer.as_json) - ensure - @association.serializer_class = @old_serializer end end end