From df481b2b3564ce06a83fe9a6ac31ce1054e1d1b1 Mon Sep 17 00:00:00 2001 From: Jorge Bejar Date: Thu, 9 Jan 2014 15:30:19 -0200 Subject: [PATCH] Don't memoize association serializer --- lib/active_model/serializer/associations.rb | 43 ++++++++++++++----- .../array_serializer/serialization_test.rb | 30 +++++++++++++ .../active_model/serializer/has_many_test.rb | 6 +-- .../active_model/serializer/has_one_test.rb | 4 +- .../active_model/serializer/scope_test.rb | 2 +- 5 files changed, 69 insertions(+), 16 deletions(-) diff --git a/lib/active_model/serializer/associations.rb b/lib/active_model/serializer/associations.rb index 91544721..d377119d 100644 --- a/lib/active_model/serializer/associations.rb +++ b/lib/active_model/serializer/associations.rb @@ -20,11 +20,11 @@ module ActiveModel @embedded_key = options[:root] || name serializer = @options[:serializer] - @serializer_class = serializer.is_a?(String) ? serializer.constantize : serializer + @serializer_from_options = serializer.is_a?(String) ? serializer.constantize : serializer end attr_reader :name, :embed_ids, :embed_objects - attr_accessor :embed_in_root, :embed_key, :key, :embedded_key, :root_key, :serializer_class, :options + attr_accessor :embed_in_root, :embed_key, :key, :embedded_key, :root_key, :serializer_from_options, :options alias embed_ids? embed_ids alias embed_objects? embed_objects alias embed_in_root? embed_in_root @@ -34,8 +34,16 @@ module ActiveModel @embed_objects = embed == :object || embed == :objects end + def serializer_from_object(object) + Serializer.serializer_for(object) + end + + def default_serializer + DefaultSerializer + end + def build_serializer(object, options = {}) - @serializer_class.new(object, options.merge(@options)) + serializer_class(object).new(object, options.merge(self.options)) end class HasOne < Association @@ -45,8 +53,11 @@ module ActiveModel @key ||= "#{name}_id" end + def serializer_class(object) + serializer_from_options || serializer_from_object(object) || default_serializer + end + def build_serializer(object, options = {}) - @serializer_class ||= Serializer.serializer_for(object) || DefaultSerializer options[:_wrap_in_array] = embed_in_root? super end @@ -59,15 +70,27 @@ module ActiveModel @key ||= "#{name.to_s.singularize}_ids" end - def build_serializer(object, options = {}) - if @serializer_class && !(@serializer_class <= ArraySerializer) - @options[:each_serializer] = @serializer_class - @serializer_class = ArraySerializer + def serializer_class(object) + if use_array_serializer? + ArraySerializer else - @serializer_class ||= ArraySerializer + serializer_from_options end + end - super + def options + if use_array_serializer? + { each_serializer: serializer_from_options }.merge! super + else + super + end + end + + private + + def use_array_serializer? + !serializer_from_options || + serializer_from_options && !(serializer_from_options <= ArraySerializer) end end end diff --git a/test/unit/active_model/array_serializer/serialization_test.rb b/test/unit/active_model/array_serializer/serialization_test.rb index 46ea3fcb..2df9ef08 100644 --- a/test/unit/active_model/array_serializer/serialization_test.rb +++ b/test/unit/active_model/array_serializer/serialization_test.rb @@ -78,6 +78,36 @@ module ActiveModel ensure PostSerializer._associations[:comments] = @old_association end + + def test_embed_object_for_has_one_association_with_nil_value + @association = UserSerializer._associations[:profile] + @old_association = @association.dup + + @association.embed = :objects + + @user1 = User.new({ name: 'User 1', email: 'email1@server.com' }) + @user2 = User.new({ name: 'User 2', email: 'email2@server.com' }) + + class << @user1 + def profile + nil + end + end + + class << @user2 + def profile + @profile ||= Profile.new(name: 'Name 1', description: 'Desc 1') + end + end + + @serializer = ArraySerializer.new([@user1, @user2]) #, root: :posts) + assert_equal([ + { name: "User 1", email: "email1@server.com", profile: nil }, + { name: "User 2", email: "email2@server.com", profile: { name: 'Name 1', description: 'Desc 1' } } + ], @serializer.as_json) + ensure + UserSerializer._associations[:profile] = @old_association + end end end end diff --git a/test/unit/active_model/serializer/has_many_test.rb b/test/unit/active_model/serializer/has_many_test.rb index 7c94cd67..8d05d7b1 100644 --- a/test/unit/active_model/serializer/has_many_test.rb +++ b/test/unit/active_model/serializer/has_many_test.rb @@ -128,7 +128,7 @@ module ActiveModel def test_associations_using_a_given_serializer @association.embed = :ids @association.embed_in_root = true - @association.serializer_class = Class.new(ActiveModel::Serializer) do + @association.serializer_from_options = Class.new(ActiveModel::Serializer) do def content object.read_attribute_for_serialization(:content) + '!' end @@ -145,7 +145,7 @@ module ActiveModel def test_associations_embedding_ids_using_a_given_array_serializer @association.embed = :ids @association.embed_in_root = true - @association.serializer_class = Class.new(ActiveModel::ArraySerializer) do + @association.serializer_from_options = Class.new(ActiveModel::ArraySerializer) do def serializable_object { my_content: ['fake'] } end @@ -158,7 +158,7 @@ module ActiveModel end def test_associations_embedding_objects_using_a_given_array_serializer - @association.serializer_class = Class.new(ActiveModel::ArraySerializer) do + @association.serializer_from_options = Class.new(ActiveModel::ArraySerializer) do def serializable_object { my_content: ['fake'] } end diff --git a/test/unit/active_model/serializer/has_one_test.rb b/test/unit/active_model/serializer/has_one_test.rb index 059d2646..a090a15c 100644 --- a/test/unit/active_model/serializer/has_one_test.rb +++ b/test/unit/active_model/serializer/has_one_test.rb @@ -119,7 +119,7 @@ module ActiveModel def test_associations_embedding_ids_using_a_given_serializer @association.embed = :ids @association.embed_in_root = true - @association.serializer_class = Class.new(ActiveModel::Serializer) do + @association.serializer_from_options = Class.new(ActiveModel::Serializer) do def name 'fake' end @@ -134,7 +134,7 @@ module ActiveModel end def test_associations_embedding_objects_using_a_given_serializer - @association.serializer_class = Class.new(ActiveModel::Serializer) do + @association.serializer_from_options = Class.new(ActiveModel::Serializer) do def name 'fake' end diff --git a/test/unit/active_model/serializer/scope_test.rb b/test/unit/active_model/serializer/scope_test.rb index dea6c114..298b686e 100644 --- a/test/unit/active_model/serializer/scope_test.rb +++ b/test/unit/active_model/serializer/scope_test.rb @@ -31,7 +31,7 @@ module ActiveModel end def test_scope_passed_through - @association.serializer_class = Class.new(ActiveModel::Serializer) do + @association.serializer_from_options = Class.new(ActiveModel::Serializer) do def name scope end