From e650863c6d342a58ba728e75e73181c99456fac5 Mon Sep 17 00:00:00 2001 From: Stanley Stuart Date: Wed, 13 Aug 2014 11:27:16 -0500 Subject: [PATCH] fix tests from rebasing master for embed_namespace --- README.md | 63 +++++++++++++++++++ lib/active_model/serializer.rb | 29 ++++++++- lib/active_model/serializer/associations.rb | 6 +- .../active_model/serializer/has_many_test.rb | 57 +++++++++++++++++ .../active_model/serializer/has_one_test.rb | 41 ++++++++++++ 5 files changed, 193 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3f254247..e6d5b694 100644 --- a/README.md +++ b/README.md @@ -522,6 +522,33 @@ Now, any associations will be supplied as an Array of IDs: } ``` +You may also choose to embed the IDs by the association's name underneath an +`embed_key` for the resource. For example, say we want to change `comment_ids` +to `comments` underneath a `links` key: + +```ruby +class PostSerializer < ActiveModel::Serializer + attributes :id, :title, :body + + has_many :comments, embed: ids, embed_namespace: :links +end +``` + +The JSON will look like this: + +```json +{ + "post": { + "id": 1, + "title": "New post", + "body": "A body!", + "links": { + "comments": [ 1, 2, 3 ] + } + } +} +``` + Alternatively, you can choose to embed only the ids or the associated objects per association: ```ruby @@ -589,6 +616,42 @@ this: } ``` +If you would like to namespace association JSON underneath a certain key in +the root document (say, `linked`), you can specify an `embed_in_root_key`: + +```ruby +class PostSerializer < ActiveModel::Serializer + embed: ids, include: true, embed_in_root_key: :linked + + attributes: :id, :title, :body + has_many :comments, :tags +end +``` + +The above would yield the following JSON document: + +```json +{ + "post": { + "id": 1, + "title": "New post", + "body": "A body!", + "comment_ids": [ 1, 2 ] + }, + "linked": { + "comments": [ + { "id": 1, "body": "what a dumb post", "tag_ids": [ 1, 2 ] }, + { "id": 2, "body": "i liked it", "tag_ids": [ 1, 3 ] }, + ], + "tags": [ + { "id": 1, "name": "short" }, + { "id": 2, "name": "whiny" }, + { "id": 3, "name": "happy" } + ] + } +} +``` + When side-loading data, your serializer cannot have the `{ root: false }` option, as this would lead to invalid JSON. If you do not have a root key, the `include` instruction will be ignored diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index bd1a3ac5..0d7ae580 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -24,9 +24,21 @@ module ActiveModel end end + EMBED_IN_ROOT_OPTIONS = [ + :include, + :embed_in_root, + :embed_in_root_key, + :embed_namespace + ].freeze + def embed(type, options={}) CONFIG.embed = type - CONFIG.embed_in_root = true if options[:embed_in_root] || options[:include] + if EMBED_IN_ROOT_OPTIONS.any? { |opt| options[opt].present? } + CONFIG.embed_in_root = true + end + if options[:embed_in_root_key].present? + CONFIG.embed_in_root_key = options[:embed_in_root_key] + end ActiveSupport::Deprecation.warn <<-WARN ** Notice: embed is deprecated. ** The use of .embed method on a Serializer will be soon removed, as this should have a global scope and not a class scope. @@ -141,8 +153,17 @@ end associations.each_with_object({}) do |(name, association), hash| if included_associations.include? name if association.embed_ids? - hash[association.key] = serialize_ids association + ids = serialize_ids association + if association.embed_namespace? + hash = hash[association.embed_namespace] ||= {} + hash[association.key] = ids + else + hash[association.key] = ids + end elsif association.embed_objects? + if association.embed_namespace? + hash = hash[association.embed_namespace] ||= {} + end hash[association.embedded_key] = serialize association end end @@ -165,6 +186,9 @@ end associations.each_with_object({}) do |(name, association), hash| if included_associations.include? name if association.embed_in_root? + if association.embed_in_root_key? + hash = hash[association.embed_in_root_key] ||= {} + end association_serializer = build_serializer(association) hash.merge!(association_serializer.embedded_in_root_associations) {|key, oldval, newval| [newval, oldval].flatten } @@ -231,4 +255,5 @@ end end alias_method :serializable_hash, :serializable_object end + end diff --git a/lib/active_model/serializer/associations.rb b/lib/active_model/serializer/associations.rb index 3b6e86b2..44d7c84f 100644 --- a/lib/active_model/serializer/associations.rb +++ b/lib/active_model/serializer/associations.rb @@ -18,16 +18,20 @@ module ActiveModel @embed_key = options[:embed_key] || :id @key = options[:key] @embedded_key = options[:root] || name + @embed_in_root_key = options.fetch(:embed_in_root_key) { CONFIG.embed_in_root_key } + @embed_namespace = options.fetch(:embed_namespace) { CONFIG.embed_namespace } serializer = @options[:serializer] @serializer_from_options = serializer.is_a?(String) ? serializer.constantize : serializer end attr_reader :name, :embed_ids, :embed_objects - attr_accessor :embed_in_root, :embed_key, :key, :embedded_key, :root_key, :serializer_from_options, :options, :key_format + attr_accessor :embed_in_root, :embed_key, :key, :embedded_key, :root_key, :serializer_from_options, :options, :key_format, :embed_in_root_key, :embed_namespace alias embed_ids? embed_ids alias embed_objects? embed_objects alias embed_in_root? embed_in_root + alias embed_in_root_key? embed_in_root_key + alias embed_namespace? embed_namespace def embed=(embed) @embed_ids = embed == :id || embed == :ids diff --git a/test/unit/active_model/serializer/has_many_test.rb b/test/unit/active_model/serializer/has_many_test.rb index 460996c4..4699002d 100644 --- a/test/unit/active_model/serializer/has_many_test.rb +++ b/test/unit/active_model/serializer/has_many_test.rb @@ -168,6 +168,63 @@ module ActiveModel 'post' => { title: 'Title 1', body: 'Body 1', comments: { my_content: ['fake'] } } }, @post_serializer.as_json) end + + def test_associations_embedding_ids_including_objects_serialization_with_embed_in_root_key + @association.embed_in_root = true + @association.embed_in_root_key = :linked + @association.embed = :ids + assert_equal({ + linked: { + comments: [ + { content: 'C1' }, + { content: 'C2' } + ] + }, + 'post' => { + title: 'Title 1', body: 'Body 1', + 'comment_ids' => @post.comments.map(&:object_id) + } + }, @post_serializer.as_json) + end + + def test_associations_embedding_ids_using_embed_namespace_including_object_serialization_with_embed_in_root_key + @association.embed_in_root = true + @association.embed_in_root_key = :linked + @association.embed = :ids + @association.embed_namespace = :links + @association.key = :comments + assert_equal({ + linked: { + comments: [ + { content: 'C1' }, + { content: 'C2' } + ] + }, + 'post' => { + title: 'Title 1', body: 'Body 1', + links: { + comments: @post.comments.map(&:object_id) + } + } + }, @post_serializer.as_json) + end + + def test_associations_embedding_objects_using_embed_namespace + @association.embed = :objects + @association.embed_namespace = :links + + assert_equal({ + 'post' => { + title: 'Title 1', body: 'Body 1', + links: { + comments: [ + { content: 'C1' }, + { content: 'C2' } + ] + } + } + }, @post_serializer.as_json) + end 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 2d49aa77..ff922894 100644 --- a/test/unit/active_model/serializer/has_one_test.rb +++ b/test/unit/active_model/serializer/has_one_test.rb @@ -161,6 +161,47 @@ module ActiveModel 'user' => { name: 'Name 1', email: 'mail@server.com', profile: { name: 'fake' } } }, @user_serializer.as_json) end + + def test_associations_embedding_ids_using_embed_namespace + @association.embed_namespace = :links + @association.embed = :ids + @association.key = :profile + assert_equal({ + 'user' => { + name: 'Name 1', email: 'mail@server.com', + links: { + profile: @user.profile.object_id + } + } + }, @user_serializer.as_json) + end + + def test_asociations_embedding_objects_using_embed_namespace + @association.embed_namespace = :links + @association.embed = :objects + assert_equal({ + 'user' => { + name: 'Name 1', email: 'mail@server.com', + links: { + profile: { name: 'N1', description: 'D1' } + } + } + }, @user_serializer.as_json) + end + + def test_associations_embedding_ids_using_embed_namespace_and_embed_in_root_key + @association.embed_in_root = true + @association.embed_in_root_key = :linked + @association.embed = :ids + assert_equal({ + 'user' => { + name: 'Name 1', email: 'mail@server.com', 'profile_id' => @user.profile.object_id + }, + linked: { + 'profiles' => [ { name: 'N1', description: 'D1' } ] + } + }, @user_serializer.as_json) + end end end end