Skip to content

Commit

Permalink
Merge pull request #962 from joaomdmoura/render-array-objects
Browse files Browse the repository at this point in the history
Rendering objects that doesn't have serializers
  • Loading branch information
joaomdmoura committed Jun 26, 2015
2 parents 01a225f + 17d560e commit 03ac94b
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 19 deletions.
15 changes: 8 additions & 7 deletions lib/action_controller/serialization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,17 +39,18 @@ def use_adapter?
options.partition { |k, _| ADAPTER_OPTION_KEYS.include? k }.map { |h| Hash[h] }

if use_adapter? && (serializer = get_serializer(resource))

@_serializer_opts[:scope] ||= serialization_scope
@_serializer_opts[:scope_name] = _serialization_scope

# omg hax
object = serializer.new(resource, @_serializer_opts)
adapter = ActiveModel::Serializer::Adapter.create(object, @_adapter_opts)
super(adapter, options)
else
super(resource, options)
begin
serialized = serializer.new(resource, @_serializer_opts)
rescue ActiveModel::Serializer::ArraySerializer::NoSerializerError
else
resource = ActiveModel::Serializer::Adapter.create(serialized, @_adapter_opts)
end
end

super(resource, options)
end
end

Expand Down
14 changes: 10 additions & 4 deletions lib/active_model/serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -206,10 +206,16 @@ def each_association(&block)
serializer_class = ActiveModel::Serializer.serializer_for(association_value, association_options)

if serializer_class
serializer = serializer_class.new(
association_value,
options.except(:serializer).merge(serializer_from_options(association_options))
)
begin
serializer = serializer_class.new(
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)
association_options[:association_options][:virtual_value] = association_value
end
Expand Down
8 changes: 7 additions & 1 deletion lib/active_model/serializer/array_serializer.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module ActiveModel
class Serializer
class ArraySerializer
NoSerializerError = Class.new(StandardError)
include Enumerable
delegate :each, to: :@objects

Expand All @@ -13,7 +14,12 @@ def initialize(objects, options = {})
:serializer,
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
@meta = options[:meta]
@meta_key = options[:meta_key]
Expand Down
22 changes: 22 additions & 0 deletions test/action_controller/serialization_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ def render_object_with_cache_enabled
render json: @post
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
@post.updated_at = DateTime.now

Expand Down Expand Up @@ -160,6 +168,20 @@ def test_render_using_default_root
assert_equal expected.to_json, @response.body
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
get :render_array_using_implicit_serializer
assert_equal 'application/json', @response.content_type
Expand Down
23 changes: 17 additions & 6 deletions test/adapter/json/has_many_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class HasManyTestTest < Minitest::Test
def setup
ActionController::Base.cache_store.clear
@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')
@second_comment = Comment.new(id: 2, body: 'ZOMG ANOTHER COMMENT')
@post.comments = [@first_comment, @second_comment]
Expand All @@ -17,20 +17,31 @@ def setup
@second_comment.post = @post
@blog = Blog.new(id: 1, name: "My Blog!!")
@post.blog = @blog

@serializer = PostSerializer.new(@post)
@adapter = ActiveModel::Serializer::Adapter::Json.new(@serializer)
@tag = Tag.new(id: 1, name: "#hash_tag")
@post.tags = [@tag]
end

def test_has_many
serializer = PostSerializer.new(@post)
adapter = ActiveModel::Serializer::Adapter::Json.new(serializer)
assert_equal([
{id: 1, body: 'ZOMG A 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

19 changes: 18 additions & 1 deletion test/adapter/json_api/has_many_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ def setup
@blog.articles = [@post]
@post.blog = @blog
@post_without_comments.blog = nil

@tag = Tag.new(id: 1, name: "#hash_tag")
@post.tags = [@tag]
@serializer = PostSerializer.new(@post)
@adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer)
end
Expand Down Expand Up @@ -95,6 +96,7 @@ def test_include_type_for_association_when_different_than_name
serializer = BlogSerializer.new(@blog)
adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer)
actual = adapter.serializable_hash[:data][:relationships][:articles]

expected = {
data: [{
type: "posts",
Expand All @@ -103,6 +105,21 @@ def test_include_type_for_association_when_different_than_name
}
assert_equal expected, actual
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
Expand Down
7 changes: 7 additions & 0 deletions test/fixtures/poro.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ class ProfilePreviewSerializer < ActiveModel::Serializer
User = Class.new(Model)
Location = Class.new(Model)
Place = Class.new(Model)
Tag = Class.new(Model)
Comment = Class.new(Model) do
# Uses a custom non-time-based cache key
def cache_key
Expand Down Expand Up @@ -224,6 +225,12 @@ def self.root_name
belongs_to :author, serializer: AuthorPreviewSerializer
end

PostWithTagsSerializer = Class.new(ActiveModel::Serializer) do
attributes :id

has_many :tags
end

Spam::UnrelatedLinkSerializer = Class.new(ActiveModel::Serializer) do
attributes :id
end
Expand Down
10 changes: 10 additions & 0 deletions test/serializers/associations_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@ def setup
@author.roles = []
@blog = Blog.new({ name: 'AMS Blog' })
@post = Post.new({ title: 'New Post', body: 'Body' })
@tag = Tag.new({name: '#hashtagged'})
@comment = Comment.new({ id: 1, body: 'ZOMG A COMMENT' })
@post.comments = [@comment]
@post.tags = [@tag]
@post.blog = @blog
@comment.post = @post
@comment.author = nil
Expand Down Expand Up @@ -65,6 +67,14 @@ def test_has_many_and_has_one
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
@post_serializer.each_association do |name, association|
if name == :comments
Expand Down

0 comments on commit 03ac94b

Please sign in to comment.