From 9fa716e45214ab5add156fbc1957ff41a7544230 Mon Sep 17 00:00:00 2001 From: Adman65 Date: Mon, 12 Dec 2011 13:11:36 +0100 Subject: [PATCH 1/6] Fixes #12 --- lib/active_model/serializer.rb | 20 ++++++++++++++++++-- test/serializer_test.rb | 30 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 474b2d9d..d52d1bee 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -72,6 +72,10 @@ module ActiveModel def key options[:key] || name end + + def polymorphic? + options[:polymorphic] + end end class HasMany < Config #:nodoc: @@ -93,7 +97,14 @@ module ActiveModel class HasOne < Config #:nodoc: def serialize(object, scope) - object && serializer.new(object, scope).serializable_hash + return unless object + + if polymorphic? + serializer_class = "#{object.class.to_s}Serializer".constantize + serializer_class.new(object, scope).serializable_hash + else + serializer.new(object, scope).serializable_hash + end end def serialize_ids(object, scope) @@ -134,7 +145,7 @@ module ActiveModel class_eval "def #{attr}() object.#{attr} end", __FILE__, __LINE__ end - options[:serializer] ||= begin + options[:serializer] ||= options[:polymorphic] || begin serializer_class = (options[:key] || attr).to_s.classify const_get("#{serializer_class}Serializer") end @@ -281,6 +292,11 @@ module ActiveModel _associations.each do |association| associated_object = send(association.name) hash[association.key] = association.serialize(associated_object, scope) + + if association.polymorphic? && associated_object + polymorphic_type = associated_object.class.to_s.split('::').last + hash["#{association.name}_type".to_sym] = polymorphic_type + end end hash diff --git a/test/serializer_test.rb b/test/serializer_test.rb index b4e50161..acefbb5c 100644 --- a/test/serializer_test.rb +++ b/test/serializer_test.rb @@ -680,4 +680,34 @@ class SerializerTest < ActiveModel::TestCase } }, hash.as_json) end + + class PolymorphicUser < User ; end + + class PolymorphicUserSerializer < ActiveModel::Serializer + attributes :first_name, :last_name + end + + def test_polymorphic_has_one + polymorphic_blog = Class.new do + attr_accessor :writer + end + + polymorphic_serializer = Class.new(ActiveModel::Serializer) do + has_one :writer, :polymorphic => true + end + + user = PolymorphicUser.new + blog = polymorphic_blog.new + blog.writer = user + + serializer = polymorphic_serializer.new(blog, user) + + assert_equal({ + :writer_type => 'PolymorphicUser', + :writer => { + :first_name => "Jose", + :last_name => "Valim" + } + }, serializer.as_json) + end end From 638614ffde52159c616d61c4e704df414645da0e Mon Sep 17 00:00:00 2001 From: Adman65 Date: Mon, 12 Dec 2011 14:33:18 +0100 Subject: [PATCH 2/6] Move polymorphic type into the serializable_hash --- lib/active_model/serializer.rb | 8 +++++--- test/serializer_test.rb | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index d52d1bee..16eb7d87 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -100,8 +100,12 @@ module ActiveModel return unless object if polymorphic? + polymorphic_type = object.class.to_s.split('::').last serializer_class = "#{object.class.to_s}Serializer".constantize - serializer_class.new(object, scope).serializable_hash + + serializer_class.new(object, scope).serializable_hash.merge({ + "#{name}_type".to_sym => polymorphic_type + }) else serializer.new(object, scope).serializable_hash end @@ -294,8 +298,6 @@ module ActiveModel hash[association.key] = association.serialize(associated_object, scope) if association.polymorphic? && associated_object - polymorphic_type = associated_object.class.to_s.split('::').last - hash["#{association.name}_type".to_sym] = polymorphic_type end end diff --git a/test/serializer_test.rb b/test/serializer_test.rb index acefbb5c..bb21d533 100644 --- a/test/serializer_test.rb +++ b/test/serializer_test.rb @@ -703,8 +703,8 @@ class SerializerTest < ActiveModel::TestCase serializer = polymorphic_serializer.new(blog, user) assert_equal({ - :writer_type => 'PolymorphicUser', :writer => { + :writer_type => 'PolymorphicUser', :first_name => "Jose", :last_name => "Valim" } From 1e32090477f1fd8c19b676a77459a246274b265d Mon Sep 17 00:00:00 2001 From: Adman65 Date: Mon, 12 Dec 2011 14:41:34 +0100 Subject: [PATCH 3/6] Serialize polymorphic id like a composite FK --- lib/active_model/serializer.rb | 11 ++++++++++- test/serializer_test.rb | 24 ++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 16eb7d87..8f06a8a7 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -112,7 +112,16 @@ module ActiveModel end def serialize_ids(object, scope) - object && object.read_attribute_for_serialization(:id) + return unless object + + if polymorphic? + { + :id => object.read_attribute_for_serialization(:id), + "#{name}_type".to_sym => object.class.to_s.split('::').last + } + else + object.read_attribute_for_serialization(:id) + end end end end diff --git a/test/serializer_test.rb b/test/serializer_test.rb index bb21d533..99b030e2 100644 --- a/test/serializer_test.rb +++ b/test/serializer_test.rb @@ -710,4 +710,28 @@ class SerializerTest < ActiveModel::TestCase } }, serializer.as_json) end + + def test_polymorphic_has_one_with_ids + polymorphic_blog = Class.new do + attr_accessor :writer + end + + polymorphic_serializer = Class.new(ActiveModel::Serializer) do + embed :ids + has_one :writer, :polymorphic => true + end + + user = PolymorphicUser.new :id => 1 + blog = polymorphic_blog.new + blog.writer = user + + serializer = polymorphic_serializer.new(blog, user) + + assert_equal({ + :writer => { + :writer_type => 'PolymorphicUser', + :id => 1 + } + }, serializer.as_json) + end end From 75516ecb48d682dfc1c0b055709772eac79d1c39 Mon Sep 17 00:00:00 2001 From: Adman65 Date: Mon, 12 Dec 2011 14:57:12 +0100 Subject: [PATCH 4/6] Demodulize --- lib/active_model/serializer.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 8f06a8a7..f8e265e3 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -100,7 +100,7 @@ module ActiveModel return unless object if polymorphic? - polymorphic_type = object.class.to_s.split('::').last + polymorphic_type = object.class.to_s.demodulize serializer_class = "#{object.class.to_s}Serializer".constantize serializer_class.new(object, scope).serializable_hash.merge({ @@ -117,7 +117,7 @@ module ActiveModel if polymorphic? { :id => object.read_attribute_for_serialization(:id), - "#{name}_type".to_sym => object.class.to_s.split('::').last + "#{name}_type".to_sym => object.class.to_s.demodulize } else object.read_attribute_for_serialization(:id) From 54d3f2edf09c1d57da3ed40a1ad293ef3fd5a1b4 Mon Sep 17 00:00:00 2001 From: adman65 Date: Tue, 3 Jan 2012 13:26:47 +0200 Subject: [PATCH 5/6] Add polymorphic key to utility method --- lib/active_model/serializer.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index baf6d24b..d59abc58 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -120,7 +120,7 @@ module ActiveModel def serialize(object, scope, context, options) if polymorphic? if object - find_serializable(object, scope, context, options).as_json(:root => object.class.to_s.demodulize.underscore.to_sym) + find_serializable(object, scope, context, options).as_json(:root => polymorphic_key(object)) else {} end @@ -131,10 +131,9 @@ module ActiveModel def serialize_ids(object, scope) - if polymorphic? { - object.class.to_s.demodulize.underscore.to_sym => object.read_attribute_for_serialization(:id), + polymorphic_key(object) => object.read_attribute_for_serialization(:id), } elsif object { key => object.read_attribute_for_serialization(:id) } @@ -142,6 +141,10 @@ module ActiveModel { key => nil } end end + + def polymorphic_key(object) + object.class.to_s.demodulize.underscore.to_sym + end end end From 09bb41fbdb8bb7d4cf414d90f43e324908fac801 Mon Sep 17 00:00:00 2001 From: adman65 Date: Tue, 3 Jan 2012 13:37:39 +0200 Subject: [PATCH 6/6] Add test cases for nil polymorphic associations --- lib/active_model/serializer.rb | 4 +++- test/serializer_test.rb | 39 ++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index d59abc58..fbbfe9da 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -131,10 +131,12 @@ module ActiveModel def serialize_ids(object, scope) - if polymorphic? + if polymorphic? && object { polymorphic_key(object) => object.read_attribute_for_serialization(:id), } + elsif polymorphic? && !object + { } elsif object { key => object.read_attribute_for_serialization(:id) } else diff --git a/test/serializer_test.rb b/test/serializer_test.rb index d502b226..f8ef7d1a 100644 --- a/test/serializer_test.rb +++ b/test/serializer_test.rb @@ -667,6 +667,25 @@ class SerializerTest < ActiveModel::TestCase }, serializer.as_json) end + def test_polymorphic_has_one_with_nil + polymorphic_blog = Class.new do + attr_accessor :writer + end + + polymorphic_serializer = Class.new(ActiveModel::Serializer) do + has_one :writer, :polymorphic => true + end + + user = PolymorphicUser.new + blog = polymorphic_blog.new + blog.writer = nil + + serializer = polymorphic_serializer.new(blog, user) + + assert_equal({ + }, serializer.as_json) + end + def test_polymorphic_has_one_with_ids polymorphic_blog = Class.new do attr_accessor :writer @@ -688,6 +707,26 @@ class SerializerTest < ActiveModel::TestCase }, serializer.as_json) end + def test_polymorphic_has_one_id_with_nil + polymorphic_blog = Class.new do + attr_accessor :writer + end + + polymorphic_serializer = Class.new(ActiveModel::Serializer) do + embed :ids + has_one :writer, :polymorphic => true + end + + user = PolymorphicUser.new + blog = polymorphic_blog.new + blog.writer = nil + + serializer = polymorphic_serializer.new(blog, user) + + assert_equal({ + }, serializer.as_json) + end + def test_root_provided_in_options author_serializer = Class.new(ActiveModel::Serializer) do attributes :id, :name