Adding 'embed_key' option to allow embedding attributes other than ID

This commit is contained in:
Jeremy Redburn 2013-01-28 09:41:46 -05:00
parent d638e21c8c
commit 7cd7d295e0
3 changed files with 134 additions and 18 deletions

View File

@ -535,6 +535,34 @@ This would generate JSON that would look like this:
}
```
You can also specify a different attribute to use rather than the ID of the
objects:
```ruby
class PostSerializer < ActiveModel::Serializer
embed :ids, :include => true
attributes :id, :title, :body
has_many :comments, :embed_key => :external_id
end
```
This would generate JSON that would look like this:
```json
{
"post": {
"id": 1,
"title": "New post",
"body": "A body!",
"comment_ids": [ "COMM001" ]
},
"comments": [
{ "id": 1, "external_id": "COMM001", "body": "what a dumb post" }
]
}
```
**NOTE**: The `embed :ids` mechanism is primary useful for clients that process
data in bulk and load it into a local store. For these clients, the ability to
easily see all of the data per type, rather than having to recursively scan the

View File

@ -103,6 +103,14 @@ module ActiveModel
end
end
def embed_key
if key = option(:embed_key)
key
else
:id
end
end
def serialize
associated_object.map do |item|
find_serializable(item).serializable_hash
@ -120,11 +128,11 @@ module ActiveModel
# return collection.ids if collection.respond_to?(:ids)
ids_key = "#{key.to_s.singularize}_ids"
if !option(:include) && source_serializer.object.respond_to?(ids_key)
if !option(:include) && !option(:embed_key) && source_serializer.object.respond_to?(ids_key)
source_serializer.object.send(ids_key)
else
associated_object.map do |item|
item.read_attribute_for_serialization(:id)
item.read_attribute_for_serialization(embed_key)
end
end
end
@ -163,6 +171,14 @@ module ActiveModel
end
end
def embed_key
if key = option(:embed_key)
key
else
:id
end
end
def polymorphic_key
associated_object.class.to_s.demodulize.underscore.to_sym
end
@ -191,15 +207,15 @@ module ActiveModel
if associated_object
{
:type => polymorphic_key,
:id => associated_object.read_attribute_for_serialization(:id)
:id => associated_object.read_attribute_for_serialization(embed_key)
}
else
nil
end
elsif source_serializer.object.respond_to?("#{name}_id")
elsif !option(:embed_key) && source_serializer.object.respond_to?("#{name}_id")
source_serializer.object.send("#{name}_id")
elsif associated_object
associated_object.read_attribute_for_serialization(:id)
associated_object.read_attribute_for_serialization(embed_key)
else
nil
end

View File

@ -34,12 +34,12 @@ class AssociationTest < ActiveModel::TestCase
@root_hash = {}
@post = Model.new(:title => "New Post", :body => "Body")
@comment = Model.new(:id => 1, :body => "ZOMG A COMMENT")
@comment = Model.new(:id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT")
@post.comments = [ @comment ]
@post.comment = @comment
@comment_serializer_class = def_serializer do
attributes :id, :body
attributes :id, :external_id, :body
end
@post_serializer_class = def_serializer do
@ -75,7 +75,7 @@ class AssociationTest < ActiveModel::TestCase
assert_equal({
:comments => [
{ :id => 1, :body => "ZOMG A COMMENT" }
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
]
}, @root_hash)
end
@ -105,7 +105,7 @@ class AssociationTest < ActiveModel::TestCase
}, @hash)
assert_equal({
:comments => [{ :id => 1, :body => "ZOMG A COMMENT" }]
:comments => [{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }]
}, @root_hash)
end
end
@ -124,7 +124,7 @@ class AssociationTest < ActiveModel::TestCase
assert_equal({
:comments => [
{ :id => 1, :body => "ZOMG A COMMENT" }
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
]
}, @root_hash)
end
@ -142,7 +142,7 @@ class AssociationTest < ActiveModel::TestCase
assert_equal({
:comments => [
{ :id => 1, :body => "ZOMG A COMMENT" }
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
]
}, @root_hash)
end
@ -160,7 +160,7 @@ class AssociationTest < ActiveModel::TestCase
assert_equal({
:comments => [
{ :id => 1, :body => "ZOMG A COMMENT" }
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
]
}, @root_hash)
end
@ -178,7 +178,79 @@ class AssociationTest < ActiveModel::TestCase
assert_equal({
:comments => [
{ :id => 1, :body => "ZOMG A COMMENT" }
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
]
}, @root_hash)
end
def test_with_default_has_many_with_custom_embed_key
@post_serializer_class.class_eval do
has_many :comments, :embed_key => :external_id
end
include! :comments
assert_equal({
:comment_ids => [ "COMM001" ]
}, @hash)
assert_equal({
:comments => [
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
]
}, @root_hash)
end
def test_with_default_has_one_with_custom_embed_key
@post_serializer_class.class_eval do
has_one :comment, :embed_key => :external_id
end
include! :comment
assert_equal({
:comment_id => "COMM001"
}, @hash)
assert_equal({
:comments => [
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
]
}, @root_hash)
end
def test_with_default_has_many_with_custom_key_and_custom_embed_key
@post_serializer_class.class_eval do
has_many :comments, :key => :custom_comments, :embed_key => :external_id
end
include! :comments
assert_equal({
:custom_comments => [ "COMM001" ]
}, @hash)
assert_equal({
:comments => [
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
]
}, @root_hash)
end
def test_with_default_has_one_with_custom_key_and_custom_embed_key
@post_serializer_class.class_eval do
has_one :comment, :key => :custom_comment, :embed_key => :external_id
end
include! :comment
assert_equal({
:custom_comment => "COMM001"
}, @hash)
assert_equal({
:comments => [
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
]
}, @root_hash)
end
@ -192,7 +264,7 @@ class AssociationTest < ActiveModel::TestCase
assert_equal({
:comments => [
{ :id => 1, :body => "ZOMG A COMMENT" }
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
]
}, @hash)
@ -237,7 +309,7 @@ class AssociationTest < ActiveModel::TestCase
assert_equal({
:comments => [
{ :id => 1, :body => "ZOMG A COMMENT" }
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
]
}, @root_hash)
end
@ -280,7 +352,7 @@ class AssociationTest < ActiveModel::TestCase
assert_equal({
:comments => [
{ :id => 1, :body => "ZOMG A COMMENT" }
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
]
}, @root_hash)
end
@ -336,7 +408,7 @@ class AssociationTest < ActiveModel::TestCase
:comment_ids => [ 1 ]
},
:comments => [
{ :id => 1, :body => "ZOMG A COMMENT" }
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
]
}, json)
end
@ -387,7 +459,7 @@ class AssociationTest < ActiveModel::TestCase
:comment_ids => [ 1 ]
},
:comments => [
{ :id => 1, :body => "ZOMG A COMMENT" }
{ :id => 1, :external_id => "COMM001", :body => "ZOMG A COMMENT" }
]
}, json)
end