From 32f87791149598dbcb840e1994f45b73a1b9a044 Mon Sep 17 00:00:00 2001 From: twinturbo Date: Sun, 22 Apr 2012 18:11:16 -0700 Subject: [PATCH 1/7] Basic rooted polymorphism --- lib/active_model/serializer.rb | 15 +++++++++++- test/serializer_test.rb | 42 ++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index b2eac4ee..7ac2874a 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -216,13 +216,26 @@ module ActiveModel end class HasOne < Config #:nodoc: + def polymorphic? + option :polymorphic + end + + def polymoprhic_key + associated_object.class.to_s.demodulize.underscore.to_sym + end + def plural_key key.to_s.pluralize.to_sym end def serialize object = associated_object - object && find_serializable(object).serializable_hash + + if object && polymorphic? + { polymoprhic_key => find_serializable(object).serializable_hash } + elsif object + find_serializable(object).serializable_hash + end end def serialize_many diff --git a/test/serializer_test.rb b/test/serializer_test.rb index 288af48a..d1473f1a 100644 --- a/test/serializer_test.rb +++ b/test/serializer_test.rb @@ -957,4 +957,46 @@ class SerializerTest < ActiveModel::TestCase :foo => true }, actual) end + + # Set up some classes for polymorphic testing + class Attachment < Model + def attachable + @attributes[:attachable] + end + end + + def tests_can_handle_polymorphism + email_serializer = Class.new(ActiveModel::Serializer) do + attributes :subject, :body + end + + email_class = Class.new(Model) do + def self.to_s + "Email" + end + + define_method :active_model_serializer do + email_serializer + end + end + + attachment_serializer = Class.new(ActiveModel::Serializer) do + attributes :name, :url + has_one :attachable, :polymorphic => true + end + + email = email_class.new :subject => 'foo', :body => 'bar' + + attachment = Attachment.new :name => 'logo.png', :url => 'http://example.com/logo.png', :attachable => email + + actual = attachment_serializer.new(attachment, {}).as_json + + assert_equal({ + :name => 'logo.png', + :url => 'http://example.com/logo.png', + :attachable => { + :email => { :subject => 'foo', :body => 'bar' } + } + }, actual) + end end From 7e96856b87ebb91f4ae453261661bbe7bdc9062c Mon Sep 17 00:00:00 2001 From: twinturbo Date: Sun, 22 Apr 2012 18:17:10 -0700 Subject: [PATCH 2/7] Support serialize polymorphic id --- lib/active_model/serializer.rb | 6 +++++- test/serializer_test.rb | 36 ++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 7ac2874a..8d6bf83a 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -245,7 +245,11 @@ module ActiveModel end def serialize_ids - if object = associated_object + object = associated_object + + if object && polymorphic? + { polymoprhic_key => object.read_attribute_for_serialization(:id) } + elsif object object.read_attribute_for_serialization(:id) else nil diff --git a/test/serializer_test.rb b/test/serializer_test.rb index d1473f1a..77dc32e7 100644 --- a/test/serializer_test.rb +++ b/test/serializer_test.rb @@ -999,4 +999,40 @@ class SerializerTest < ActiveModel::TestCase } }, actual) end + + def test_can_handle_polymoprhic_ids + email_serializer = Class.new(ActiveModel::Serializer) do + attributes :subject, :body + end + + email_class = Class.new(Model) do + def self.to_s + "Email" + end + + define_method :active_model_serializer do + email_serializer + end + end + + attachment_serializer = Class.new(ActiveModel::Serializer) do + embed :ids + attributes :name, :url + has_one :attachable, :polymorphic => true + end + + email = email_class.new :id => 1 + + attachment = Attachment.new :name => 'logo.png', :url => 'http://example.com/logo.png', :attachable => email + + actual = attachment_serializer.new(attachment, {}).as_json + + assert_equal({ + :name => 'logo.png', + :url => 'http://example.com/logo.png', + :attachable => { + :email => 1 + } + }, actual) + end end From 3ca1621011c67b2612197f8371b2ce9029695dc9 Mon Sep 17 00:00:00 2001 From: twinturbo Date: Mon, 23 Apr 2012 20:37:32 -0500 Subject: [PATCH 3/7] Add failing test for polymorphic with include --- test/serializer_test.rb | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/test/serializer_test.rb b/test/serializer_test.rb index 77dc32e7..132d0b85 100644 --- a/test/serializer_test.rb +++ b/test/serializer_test.rb @@ -1035,4 +1035,45 @@ class SerializerTest < ActiveModel::TestCase } }, actual) end + + def test_polymorphic_associations_are_included_at_root + email_serializer = Class.new(ActiveModel::Serializer) do + attributes :subject, :body + end + + email_class = Class.new(Model) do + def self.to_s + "Email" + end + + define_method :active_model_serializer do + email_serializer + end + end + + attachment_serializer = Class.new(ActiveModel::Serializer) do + embed :ids, :include => true + attributes :name, :url + has_one :attachable, :polymorphic => true + end + + email = email_class.new :id => 1, :subject => "Hello", :body => "World" + + attachment = Attachment.new :name => 'logo.png', :url => 'http://example.com/logo.png', :attachable => email + + actual = attachment_serializer.new(attachment, {}).as_json + + assert_equal({ + :name => 'logo.png', + :url => 'http://example.com/logo.png', + :attachable => { + :email => 1 + }, + :emails => [{ + :id => 1, + :subject => "Hello", + :body => "World" + }] + }, actual) + end end From 9f20fe8b3667bc99465562b806544bdcfe27a2be Mon Sep 17 00:00:00 2001 From: twinturbo Date: Mon, 23 Apr 2012 21:22:07 -0500 Subject: [PATCH 4/7] Test passes --- lib/active_model/serializer.rb | 6 +++++- test/serializer_test.rb | 14 ++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 8d6bf83a..6ca07ee9 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -225,7 +225,11 @@ module ActiveModel end def plural_key - key.to_s.pluralize.to_sym + if polymorphic? + associated_object.class.to_s.pluralize.demodulize.underscore.to_sym + else + key.to_s.pluralize.to_sym + end end def serialize diff --git a/test/serializer_test.rb b/test/serializer_test.rb index 132d0b85..16890aee 100644 --- a/test/serializer_test.rb +++ b/test/serializer_test.rb @@ -1038,7 +1038,7 @@ class SerializerTest < ActiveModel::TestCase def test_polymorphic_associations_are_included_at_root email_serializer = Class.new(ActiveModel::Serializer) do - attributes :subject, :body + attributes :subject, :body, :id end email_class = Class.new(Model) do @@ -1052,6 +1052,7 @@ class SerializerTest < ActiveModel::TestCase end attachment_serializer = Class.new(ActiveModel::Serializer) do + root :attachment embed :ids, :include => true attributes :name, :url has_one :attachable, :polymorphic => true @@ -1064,11 +1065,12 @@ class SerializerTest < ActiveModel::TestCase actual = attachment_serializer.new(attachment, {}).as_json assert_equal({ - :name => 'logo.png', - :url => 'http://example.com/logo.png', - :attachable => { - :email => 1 - }, + :attachment => { + :name => 'logo.png', + :url => 'http://example.com/logo.png', + :attachable => { + :email => 1 + }}, :emails => [{ :id => 1, :subject => "Hello", From c4e5cd547bc11b97fba87dafab79d9904a06711c Mon Sep 17 00:00:00 2001 From: twinturbo Date: Mon, 23 Apr 2012 22:01:13 -0500 Subject: [PATCH 5/7] Add test for complex polymorphic associations --- test/serializer_test.rb | 81 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/test/serializer_test.rb b/test/serializer_test.rb index 16890aee..ec11751a 100644 --- a/test/serializer_test.rb +++ b/test/serializer_test.rb @@ -963,6 +963,14 @@ class SerializerTest < ActiveModel::TestCase def attachable @attributes[:attachable] end + + def readable + @attributes[:readable] + end + + def edible + @attributes[:edible] + end end def tests_can_handle_polymorphism @@ -1078,4 +1086,77 @@ class SerializerTest < ActiveModel::TestCase }] }, actual) end + + def test_multiple_polymorphic_associations + email_serializer = Class.new(ActiveModel::Serializer) do + attributes :subject, :body, :id + end + + orange_serializer = Class.new(ActiveModel::Serializer) do + attributes :plu, :id + end + + email_class = Class.new(Model) do + def self.to_s + "Email" + end + + define_method :active_model_serializer do + email_serializer + end + end + + orange_class = Class.new(Model) do + def self.to_s + "Orange" + end + + define_method :active_model_serializer do + orange_serializer + end + end + + attachment_serializer = Class.new(ActiveModel::Serializer) do + root :attachment + embed :ids, :include => true + + attributes :name, :url + + has_one :attachable, :polymorphic => true + has_one :readable, :polymorphic => true + has_one :edible, :polymorphic => true + end + + email = email_class.new :id => 1, :subject => "Hello", :body => "World" + orange = orange_class.new :id => 1, :plu => "3027" + + attachment = Attachment.new({ + :name => 'logo.png', + :url => 'http://example.com/logo.png', + :attachable => email, + :readable => email, + :edible => orange + }) + + actual = attachment_serializer.new(attachment, {}).as_json + + assert_equal({ + :attachment => { + :name => 'logo.png', + :url => 'http://example.com/logo.png', + :attachable => { :email => 1 }, + :readable => { :email => 1 }, + :edible => { :orange => 1 } + }, + :emails => [{ + :id => 1, + :subject => "Hello", + :body => "World" + }], + :oranges => [{ + :id => 1, + :plu => "3027" + }] + }, actual) + end end From cbd7d7d38553bdbf70ff35e46dd419a09aa712f9 Mon Sep 17 00:00:00 2001 From: twinturbo Date: Mon, 23 Apr 2012 22:14:30 -0500 Subject: [PATCH 6/7] Add test for nested included polymoprhic associations --- test/serializer_test.rb | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/test/serializer_test.rb b/test/serializer_test.rb index ec11751a..b181b959 100644 --- a/test/serializer_test.rb +++ b/test/serializer_test.rb @@ -1093,7 +1093,10 @@ class SerializerTest < ActiveModel::TestCase end orange_serializer = Class.new(ActiveModel::Serializer) do + embed :ids, :include => true + attributes :plu, :id + has_one :readable, :polymorphic => true end email_class = Class.new(Model) do @@ -1111,8 +1114,12 @@ class SerializerTest < ActiveModel::TestCase "Orange" end + def readable + @attributes[:readable] + end + define_method :active_model_serializer do - orange_serializer + orange_serializer end end @@ -1128,7 +1135,7 @@ class SerializerTest < ActiveModel::TestCase end email = email_class.new :id => 1, :subject => "Hello", :body => "World" - orange = orange_class.new :id => 1, :plu => "3027" + orange = orange_class.new :id => 1, :plu => "3027", readable: email attachment = Attachment.new({ :name => 'logo.png', @@ -1141,22 +1148,25 @@ class SerializerTest < ActiveModel::TestCase actual = attachment_serializer.new(attachment, {}).as_json assert_equal({ + :emails => [{ + :subject => "Hello", + :body => "World", + :id => 1 + }], + + :oranges => [{ + :plu => "3027", + :id => 1, + :readable => { :email => 1 } + }], + :attachment => { :name => 'logo.png', :url => 'http://example.com/logo.png', :attachable => { :email => 1 }, :readable => { :email => 1 }, :edible => { :orange => 1 } - }, - :emails => [{ - :id => 1, - :subject => "Hello", - :body => "World" - }], - :oranges => [{ - :id => 1, - :plu => "3027" - }] + } }, actual) end end From f01fe149724f69c8c2df741e4b281938ca0a308b Mon Sep 17 00:00:00 2001 From: twinturbo Date: Wed, 25 Apr 2012 13:17:01 -0500 Subject: [PATCH 7/7] Fix spelling mistakes --- lib/active_model/serializer.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 6ca07ee9..21e73358 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -220,7 +220,7 @@ module ActiveModel option :polymorphic end - def polymoprhic_key + def polymorphic_key associated_object.class.to_s.demodulize.underscore.to_sym end @@ -236,7 +236,7 @@ module ActiveModel object = associated_object if object && polymorphic? - { polymoprhic_key => find_serializable(object).serializable_hash } + { polymorphic_key => find_serializable(object).serializable_hash } elsif object find_serializable(object).serializable_hash end @@ -252,7 +252,7 @@ module ActiveModel object = associated_object if object && polymorphic? - { polymoprhic_key => object.read_attribute_for_serialization(:id) } + { polymorphic_key => object.read_attribute_for_serialization(:id) } elsif object object.read_attribute_for_serialization(:id) else