From 19ac1398802ada24a9938dadc5cd1a36e4944308 Mon Sep 17 00:00:00 2001 From: Guillermo Iguaran Date: Thu, 30 Oct 2014 09:35:05 -0500 Subject: [PATCH] Handle correctly null associations null belongs_to associations are now serialized as nil instead of raise an error during serialization. --- lib/active_model/serializer.rb | 2 +- lib/active_model/serializer/adapter/json.rb | 6 +++++- lib/active_model/serializer/adapter/json_api.rb | 14 +++++++++----- test/adapter/json/belongs_to_test.rb | 11 +++++++++++ test/adapter/json/collection_test.rb | 7 +++++-- test/adapter/json/has_many_test.rb | 2 ++ test/adapter/json_api/belongs_to_test.rb | 12 ++++++++++++ test/adapter/json_api/collection_test.rb | 7 +++++-- test/adapter/json_api/has_many_test.rb | 2 ++ test/adapter/json_test.rb | 2 ++ test/fixtures/poro.rb | 1 + test/serializers/associations_test.rb | 15 +++++++++------ 12 files changed, 64 insertions(+), 17 deletions(-) diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 7050dc387..dbc2060d9 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -133,7 +133,7 @@ def each_association(&block) self.class._associations.dup.each do |name, options| association = object.send(name) serializer_class = ActiveModel::Serializer.serializer_for(association) - serializer = serializer_class.new(association) + serializer = serializer_class.new(association) if serializer_class if block_given? block.call(name, serializer, options[:options]) diff --git a/lib/active_model/serializer/adapter/json.rb b/lib/active_model/serializer/adapter/json.rb index 3b5681942..8ad1e41d6 100644 --- a/lib/active_model/serializer/adapter/json.rb +++ b/lib/active_model/serializer/adapter/json.rb @@ -13,7 +13,11 @@ def serializable_hash(options = {}) array_serializer = association @result[name] = array_serializer.map { |item| item.attributes(opts) } else - @result[name] = association.attributes(options) + if association + @result[name] = association.attributes(options) + else + @result[name] = nil + end end end end diff --git a/lib/active_model/serializer/adapter/json_api.rb b/lib/active_model/serializer/adapter/json_api.rb index 3f0057a8c..f5ff71285 100644 --- a/lib/active_model/serializer/adapter/json_api.rb +++ b/lib/active_model/serializer/adapter/json_api.rb @@ -44,13 +44,17 @@ def add_links(name, serializers, options) end def add_link(name, serializer, options) - @hash[@root][:links][name] = serializer.id.to_s + if serializer + @hash[@root][:links][name] = serializer.id.to_s - unless options[:embed] == :ids - plural_name = name.to_s.pluralize.to_sym + unless options[:embed] == :ids + plural_name = name.to_s.pluralize.to_sym - @hash[:linked][plural_name] ||= [] - @hash[:linked][plural_name].push attributes_for_serializer(serializer, options) + @hash[:linked][plural_name] ||= [] + @hash[:linked][plural_name].push attributes_for_serializer(serializer, options) + end + else + @hash[@root][:links][name] = nil end end diff --git a/test/adapter/json/belongs_to_test.rb b/test/adapter/json/belongs_to_test.rb index 498f1d986..663907dee 100644 --- a/test/adapter/json/belongs_to_test.rb +++ b/test/adapter/json/belongs_to_test.rb @@ -7,9 +7,13 @@ class Json class BelongsToTest < Minitest::Test def setup @post = Post.new(id: 42, title: 'New Post', body: 'Body') + @anonymous_post = Post.new(id: 43, title: 'Hello!!', body: 'Hello, world!!') @comment = Comment.new(id: 1, body: 'ZOMG A COMMENT') @post.comments = [@comment] + @anonymous_post.comments = [] @comment.post = @post + @post.author = @author + @anonymous_post.author = nil @serializer = CommentSerializer.new(@comment) @adapter = ActiveModel::Serializer::Adapter::Json.new(@serializer) @@ -18,6 +22,13 @@ def setup def test_includes_post assert_equal({id: 42, title: 'New Post', body: 'Body'}, @adapter.serializable_hash[:post]) end + + def test_include_nil_author + serializer = PostSerializer.new(@anonymous_post) + adapter = ActiveModel::Serializer::Adapter::Json.new(serializer) + + assert_equal({title: "Hello!!", body: "Hello, world!!", id: 43, comments: [], author: nil}, adapter.serializable_hash) + end end end end diff --git a/test/adapter/json/collection_test.rb b/test/adapter/json/collection_test.rb index 4d02f65a9..51af54489 100644 --- a/test/adapter/json/collection_test.rb +++ b/test/adapter/json/collection_test.rb @@ -6,10 +6,13 @@ class Adapter class Json class Collection < Minitest::Test def setup + @author = Author.new(id: 1, name: 'Steve K.') @first_post = Post.new(id: 1, title: 'Hello!!', body: 'Hello, world!!') @second_post = Post.new(id: 2, title: 'New Post', body: 'Body') @first_post.comments = [] @second_post.comments = [] + @first_post.author = @author + @second_post.author = @author @serializer = ArraySerializer.new([@first_post, @second_post]) @adapter = ActiveModel::Serializer::Adapter::Json.new(@serializer) @@ -17,8 +20,8 @@ def setup def test_include_multiple_posts assert_equal([ - {title: "Hello!!", body: "Hello, world!!", id: 1, comments: []}, - {title: "New Post", body: "Body", id: 2, comments: []} + {title: "Hello!!", body: "Hello, world!!", id: 1, comments: [], author: {id: 1, name: "Steve K."}}, + {title: "New Post", body: "Body", id: 2, comments: [], author: {id: 1, name: "Steve K."}} ], @adapter.serializable_hash) end end diff --git a/test/adapter/json/has_many_test.rb b/test/adapter/json/has_many_test.rb index d1534e6b7..77f672c70 100644 --- a/test/adapter/json/has_many_test.rb +++ b/test/adapter/json/has_many_test.rb @@ -6,10 +6,12 @@ class Adapter class Json class HasManyTestTest < Minitest::Test def setup + @author = Author.new(id: 1, name: 'Steve K.') @post = Post.new(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] + @post.author = @author @first_comment.post = @post @second_comment.post = @post diff --git a/test/adapter/json_api/belongs_to_test.rb b/test/adapter/json_api/belongs_to_test.rb index 0a43e5319..58a0f6998 100644 --- a/test/adapter/json_api/belongs_to_test.rb +++ b/test/adapter/json_api/belongs_to_test.rb @@ -6,10 +6,15 @@ class Adapter class JsonApi class BelongsToTest < Minitest::Test def setup + @author = Author.new(id: 1, name: 'Steve K.') @post = Post.new(id: 42, title: 'New Post', body: 'Body') + @anonymous_post = Post.new(id: 43, title: 'Hello!!', body: 'Hello, world!!') @comment = Comment.new(id: 1, body: 'ZOMG A COMMENT') @post.comments = [@comment] + @anonymous_post.comments = [] @comment.post = @post + @post.author = @author + @anonymous_post.author = nil @serializer = CommentSerializer.new(@comment) @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer) @@ -22,6 +27,13 @@ def test_includes_post_id def test_includes_linked_post assert_equal([{id: "42", title: 'New Post', body: 'Body'}], @adapter.serializable_hash[:linked][:posts]) end + + def test_include_nil_author + serializer = PostSerializer.new(@anonymous_post) + adapter = ActiveModel::Serializer::Adapter::JsonApi.new(serializer) + + assert_equal({comments: [], author: nil}, adapter.serializable_hash[:posts][:links]) + end end end end diff --git a/test/adapter/json_api/collection_test.rb b/test/adapter/json_api/collection_test.rb index 566581a84..5eaec7a55 100644 --- a/test/adapter/json_api/collection_test.rb +++ b/test/adapter/json_api/collection_test.rb @@ -6,10 +6,13 @@ class Adapter class JsonApi class Collection < Minitest::Test def setup + @author = Author.new(id: 1, name: 'Steve K.') @first_post = Post.new(id: 1, title: 'Hello!!', body: 'Hello, world!!') @second_post = Post.new(id: 2, title: 'New Post', body: 'Body') @first_post.comments = [] @second_post.comments = [] + @first_post.author = @author + @second_post.author = @author @serializer = ArraySerializer.new([@first_post, @second_post]) @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer) @@ -17,8 +20,8 @@ def setup def test_include_multiple_posts assert_equal([ - {title: "Hello!!", body: "Hello, world!!", id: "1", links: {comments: []}}, - {title: "New Post", body: "Body", id: "2", links: {comments: []}} + {title: "Hello!!", body: "Hello, world!!", id: "1", links: {comments: [], author: "1"}}, + {title: "New Post", body: "Body", id: "2", links: {comments: [], author: "1"}} ], @adapter.serializable_hash[:posts]) end end diff --git a/test/adapter/json_api/has_many_test.rb b/test/adapter/json_api/has_many_test.rb index f558c7d46..17c9c17de 100644 --- a/test/adapter/json_api/has_many_test.rb +++ b/test/adapter/json_api/has_many_test.rb @@ -6,12 +6,14 @@ class Adapter class JsonApi class HasManyTest < Minitest::Test def setup + @author = Author.new(id: 1, name: 'Steve K.') @post = Post.new(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] @first_comment.post = @post @second_comment.post = @post + @post.author = @author @serializer = PostSerializer.new(@post) @adapter = ActiveModel::Serializer::Adapter::JsonApi.new(@serializer) diff --git a/test/adapter/json_test.rb b/test/adapter/json_test.rb index 1d2e35a64..fe573f7b4 100644 --- a/test/adapter/json_test.rb +++ b/test/adapter/json_test.rb @@ -5,12 +5,14 @@ class Serializer class Adapter class JsonTest < Minitest::Test def setup + @author = Author.new(id: 1, name: 'Steve K.') @post = Post.new(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] @first_comment.post = @post @second_comment.post = @post + @post.author = @author @serializer = PostSerializer.new(@post) @adapter = ActiveModel::Serializer::Adapter::Json.new(@serializer) diff --git a/test/fixtures/poro.rb b/test/fixtures/poro.rb index 2f4ffdbfb..ce5f345a2 100644 --- a/test/fixtures/poro.rb +++ b/test/fixtures/poro.rb @@ -43,6 +43,7 @@ class ProfileSerializer < ActiveModel::Serializer attributes :title, :body, :id has_many :comments + belongs_to :author url :comments end diff --git a/test/serializers/associations_test.rb b/test/serializers/associations_test.rb index 6d69b563c..0891f3658 100644 --- a/test/serializers/associations_test.rb +++ b/test/serializers/associations_test.rb @@ -2,7 +2,7 @@ module ActiveModel class Serializer - class AssocationsTest < Minitest::Test + class AssociationsTest < Minitest::Test class Model def initialize(hash={}) @attributes = hash @@ -25,20 +25,23 @@ def method_missing(meth, *args) def setup + @author = Author.new(name: 'Steve K.') @post = Post.new({ title: 'New Post', body: 'Body' }) @comment = Comment.new({ id: 1, body: 'ZOMG A COMMENT' }) @post.comments = [@comment] @comment.post = @post + @post.author = @author + @author.posts = [@post] - @post_serializer = PostSerializer.new(@post) + @author_serializer = AuthorSerializer.new(@author) @comment_serializer = CommentSerializer.new(@comment) end def test_has_many - assert_equal({comments: {type: :has_many, options: {}}}, @post_serializer.class._associations) - @post_serializer.each_association do |name, serializer, options| - assert_equal(:comments, name) - assert_equal({}, options) + assert_equal({posts: {type: :has_many, options: {embed: :ids}}}, @author_serializer.class._associations) + @author_serializer.each_association do |name, serializer, options| + assert_equal(:posts, name) + assert_equal({embed: :ids}, options) assert_kind_of(ActiveModel::Serializer.config.array_serializer, serializer) end end