Merge pull request #962 from joaomdmoura/render-array-objects

Rendering objects that doesn't have serializers
This commit is contained in:
João Moura 2015-06-26 02:32:04 -03:00
commit 03ac94b9b4
8 changed files with 99 additions and 19 deletions

View File

@ -39,17 +39,18 @@ module ActionController
options.partition { |k, _| ADAPTER_OPTION_KEYS.include? k }.map { |h| Hash[h] } options.partition { |k, _| ADAPTER_OPTION_KEYS.include? k }.map { |h| Hash[h] }
if use_adapter? && (serializer = get_serializer(resource)) if use_adapter? && (serializer = get_serializer(resource))
@_serializer_opts[:scope] ||= serialization_scope @_serializer_opts[:scope] ||= serialization_scope
@_serializer_opts[:scope_name] = _serialization_scope @_serializer_opts[:scope_name] = _serialization_scope
# omg hax begin
object = serializer.new(resource, @_serializer_opts) serialized = serializer.new(resource, @_serializer_opts)
adapter = ActiveModel::Serializer::Adapter.create(object, @_adapter_opts) rescue ActiveModel::Serializer::ArraySerializer::NoSerializerError
super(adapter, options) else
else resource = ActiveModel::Serializer::Adapter.create(serialized, @_adapter_opts)
super(resource, options) end
end end
super(resource, options)
end end
end end

View File

@ -206,10 +206,16 @@ module ActiveModel
serializer_class = ActiveModel::Serializer.serializer_for(association_value, association_options) serializer_class = ActiveModel::Serializer.serializer_for(association_value, association_options)
if serializer_class if serializer_class
serializer = serializer_class.new( begin
association_value, serializer = serializer_class.new(
options.except(:serializer).merge(serializer_from_options(association_options)) association_value,
) options.except(:serializer).merge(serializer_from_options(association_options))
)
rescue ActiveModel::Serializer::ArraySerializer::NoSerializerError
virtual_value = association_value
virtual_value = virtual_value.as_json if virtual_value.respond_to?(:as_json)
association_options[:association_options][:virtual_value] = virtual_value
end
elsif !association_value.nil? && !association_value.instance_of?(Object) elsif !association_value.nil? && !association_value.instance_of?(Object)
association_options[:association_options][:virtual_value] = association_value association_options[:association_options][:virtual_value] = association_value
end end

View File

@ -1,6 +1,7 @@
module ActiveModel module ActiveModel
class Serializer class Serializer
class ArraySerializer class ArraySerializer
NoSerializerError = Class.new(StandardError)
include Enumerable include Enumerable
delegate :each, to: :@objects delegate :each, to: :@objects
@ -13,7 +14,12 @@ module ActiveModel
:serializer, :serializer,
ActiveModel::Serializer.serializer_for(object) ActiveModel::Serializer.serializer_for(object)
) )
serializer_class.new(object, options.except(:serializer))
if serializer_class.nil?
fail NoSerializerError, "No serializer found for object: #{object.inspect}"
else
serializer_class.new(object, options.except(:serializer))
end
end end
@meta = options[:meta] @meta = options[:meta]
@meta_key = options[:meta_key] @meta_key = options[:meta_key]

View File

@ -47,6 +47,14 @@ module ActionController
render json: @post render json: @post
end end
def render_json_object_without_serializer
render json: {error: 'Result is Invalid'}
end
def render_json_array_object_without_serializer
render json: [{error: 'Result is Invalid'}]
end
def update_and_render_object_with_cache_enabled def update_and_render_object_with_cache_enabled
@post.updated_at = DateTime.now @post.updated_at = DateTime.now
@ -160,6 +168,20 @@ module ActionController
assert_equal expected.to_json, @response.body assert_equal expected.to_json, @response.body
end end
def test_render_json_object_without_serializer
get :render_json_object_without_serializer
assert_equal 'application/json', @response.content_type
assert_equal ({error: 'Result is Invalid'}).to_json, @response.body
end
def test_render_json_array_object_without_serializer
get :render_json_array_object_without_serializer
assert_equal 'application/json', @response.content_type
assert_equal ([{error: 'Result is Invalid'}]).to_json, @response.body
end
def test_render_array_using_implicit_serializer def test_render_array_using_implicit_serializer
get :render_array_using_implicit_serializer get :render_array_using_implicit_serializer
assert_equal 'application/json', @response.content_type assert_equal 'application/json', @response.content_type

View File

@ -8,7 +8,7 @@ module ActiveModel
def setup def setup
ActionController::Base.cache_store.clear ActionController::Base.cache_store.clear
@author = Author.new(id: 1, name: 'Steve K.') @author = Author.new(id: 1, name: 'Steve K.')
@post = Post.new(title: 'New Post', body: 'Body') @post = Post.new(id: 42, title: 'New Post', body: 'Body')
@first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT') @first_comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
@second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT') @second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
@post.comments = [@first_comment, @second_comment] @post.comments = [@first_comment, @second_comment]
@ -17,20 +17,31 @@ module ActiveModel
@second_comment.post = @post @second_comment.post = @post
@blog = Blog.new(id: 1, name: "My Blog!!") @blog = Blog.new(id: 1, name: "My Blog!!")
@post.blog = @blog @post.blog = @blog
@tag = Tag.new(id: 1, name: "#hash_tag")
@serializer = PostSerializer.new(@post) @post.tags = [@tag]
@adapter = ActiveModel::Serializer::Adapter::Json.new(@serializer)
end end
def test_has_many def test_has_many
serializer = PostSerializer.new(@post)
adapter = ActiveModel::Serializer::Adapter::Json.new(serializer)
assert_equal([ assert_equal([
{id: 1, body: 'ZOMG A COMMENT'}, {id: 1, body: 'ZOMG A COMMENT'},
{id: 2, body: 'ZOMG ANOTHER COMMENT'} {id: 2, body: 'ZOMG ANOTHER COMMENT'}
], @adapter.serializable_hash[:post][:comments]) ], adapter.serializable_hash[:post][:comments])
end
def test_has_many_with_no_serializer
serializer = PostWithTagsSerializer.new(@post)
adapter = ActiveModel::Serializer::Adapter::Json.new(serializer)
assert_equal({
id: 42,
tags: [
{"attributes"=>{"id"=>1, "name"=>"#hash_tag"}}
]
}.to_json, adapter.serializable_hash[:post_with_tags].to_json)
end end
end end
end end
end end
end end
end end

View File

@ -27,7 +27,8 @@ module ActiveModel
@blog.articles = [@post] @blog.articles = [@post]
@post.blog = @blog @post.blog = @blog
@post_without_comments.blog = nil @post_without_comments.blog = nil
@tag = Tag.new(id: 1, name: "#hash_tag")
@post.tags = [@tag]
@serializer = PostSerializer.new(@post) @serializer = PostSerializer.new(@post)
@adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer) @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer)
end end
@ -95,6 +96,7 @@ module ActiveModel
serializer = BlogSerializer.new(@blog) serializer = BlogSerializer.new(@blog)
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer) adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer)
actual = adapter.serializable_hash[:data][:relationships][:articles] actual = adapter.serializable_hash[:data][:relationships][:articles]
expected = { expected = {
data: [{ data: [{
type: "posts", type: "posts",
@ -103,6 +105,21 @@ module ActiveModel
} }
assert_equal expected, actual assert_equal expected, actual
end end
def test_has_many_with_no_serializer
serializer = PostWithTagsSerializer.new(@post)
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer)
assert_equal({
data: {
id: "1",
type: "posts",
relationships: {
tags: { data: nil }
}
}
}, adapter.serializable_hash)
end
end end
end end
end end

View File

@ -76,6 +76,7 @@ Role = Class.new(Model)
User = Class.new(Model) User = Class.new(Model)
Location = Class.new(Model) Location = Class.new(Model)
Place = Class.new(Model) Place = Class.new(Model)
Tag = Class.new(Model)
Comment = Class.new(Model) do Comment = Class.new(Model) do
# Uses a custom non-time-based cache key # Uses a custom non-time-based cache key
def cache_key def cache_key
@ -224,6 +225,12 @@ PostPreviewSerializer = Class.new(ActiveModel::Serializer) do
belongs_to :author, serializer: AuthorPreviewSerializer belongs_to :author, serializer: AuthorPreviewSerializer
end end
PostWithTagsSerializer = Class.new(ActiveModel::Serializer) do
attributes :id
has_many :tags
end
Spam::UnrelatedLinkSerializer = Class.new(ActiveModel::Serializer) do Spam::UnrelatedLinkSerializer = Class.new(ActiveModel::Serializer) do
attributes :id attributes :id
end end

View File

@ -29,8 +29,10 @@ module ActiveModel
@author.roles = [] @author.roles = []
@blog = Blog.new({ name: 'AMS Blog' }) @blog = Blog.new({ name: 'AMS Blog' })
@post = Post.new({ title: 'New Post', body: 'Body' }) @post = Post.new({ title: 'New Post', body: 'Body' })
@tag = Tag.new({name: '#hashtagged'})
@comment = Comment.new({ id: 1, body: 'ZOMG A COMMENT' }) @comment = Comment.new({ id: 1, body: 'ZOMG A COMMENT' })
@post.comments = [@comment] @post.comments = [@comment]
@post.tags = [@tag]
@post.blog = @blog @post.blog = @blog
@comment.post = @post @comment.post = @post
@comment.author = nil @comment.author = nil
@ -65,6 +67,14 @@ module ActiveModel
end end
end end
def test_has_many_with_no_serializer
PostWithTagsSerializer.new(@post).each_association do |name, serializer, options|
assert_equal name, :tags
assert_equal serializer, nil
assert_equal [{ attributes: { name: "#hashtagged" }}].to_json, options[:virtual_value].to_json
end
end
def test_serializer_options_are_passed_into_associations_serializers def test_serializer_options_are_passed_into_associations_serializers
@post_serializer.each_association do |name, association| @post_serializer.each_association do |name, association|
if name == :comments if name == :comments