From 9521e912fe0136a7f9850feff51f085c287bece2 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Thu, 23 May 2013 17:34:03 -0700 Subject: [PATCH] serialize_ids call methods on the corresponding serializer if defined --- lib/active_model/serializer.rb | 7 +-- lib/active_model/serializer/associations.rb | 24 +++++-- test/serializer_test.rb | 69 +++++++++++++++++++++ 3 files changed, 88 insertions(+), 12 deletions(-) diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 2ac8eacb..c3768f75 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -382,12 +382,7 @@ module ActiveModel association = association_class.new(name, options, self.options) if association.embed_ids? - node[association.key] = - if options[:embed_key] || self.respond_to?(name) || !self.object.respond_to?(association.id_key) - association.serialize_ids - else - self.object.read_attribute_for_serialization(association.id_key) - end + node[association.key] = association.serialize_ids if association.embed_in_root? && hash.nil? raise IncludeError.new(self.class, association.name) diff --git a/lib/active_model/serializer/associations.rb b/lib/active_model/serializer/associations.rb index 63760d41..888b94fd 100644 --- a/lib/active_model/serializer/associations.rb +++ b/lib/active_model/serializer/associations.rb @@ -34,7 +34,7 @@ module ActiveModel @embed_in_root = options[:include] serializer = options[:serializer] - @serializer = serializer.is_a?(String) ? serializer.constantize : serializer + @serializer_class = serializer.is_a?(String) ? serializer.constantize : serializer @options = options @serializer_options = serializer_options @@ -59,11 +59,11 @@ module ActiveModel private - attr_reader :embed_key, :serializer, :options, :serializer_options + attr_reader :embed_key, :serializer_class, :options, :serializer_options def find_serializable(object) - if serializer - serializer.new(object, serializer_options) + if serializer_class + serializer_class.new(object, serializer_options) elsif object.respond_to?(:active_model_serializer) && (ams = object.active_model_serializer) ams.new(object, serializer_options) else @@ -94,7 +94,12 @@ module ActiveModel def serialize_ids object.map do |item| - item.read_attribute_for_serialization(embed_key) + serializer = find_serializable(item) + if serializer.respond_to?(embed_key) + serializer.send(embed_key) + else + item.read_attribute_for_serialization(embed_key) + end end end end @@ -143,7 +148,14 @@ module ActiveModel def serialize_ids if object - id = object.read_attribute_for_serialization(embed_key) + serializer = find_serializable(object) + id = + if serializer.respond_to?(embed_key) + serializer.send(embed_key) + else + object.read_attribute_for_serialization(embed_key) + end + if polymorphic? { :type => polymorphic_key, diff --git a/test/serializer_test.rb b/test/serializer_test.rb index 6c7cf7b9..588da1c7 100644 --- a/test/serializer_test.rb +++ b/test/serializer_test.rb @@ -454,6 +454,39 @@ class SerializerTest < ActiveModel::TestCase }, json) end + def test_methods_take_priority_over_associations_and_call_the_appropriate_id_method + comment_serializer = Class.new(ActiveModel::Serializer) do + def id + "OMG" + end + end + + post_serializer = Class.new(ActiveModel::Serializer) do + attributes :title + has_many :comments, :serializer => comment_serializer + embed :ids + + def comments + object.comments[0,1] + end + end + + post = Post.new(:title => "My Post") + comments = [Comment.new(:title => "Comment1", :id => 1), Comment.new(:title => "Comment2", :id => 2)] + post.comments = comments + + post.class_eval do + define_method :comment_ids, lambda { + self.comments.map { |c| c.read_attribute_for_serialization(:id) } + } + end + json = post_serializer.new(post).as_json + assert_equal({ + :title => "My Post", + :comment_ids => ["OMG"] + }, json) + end + def test_embed_objects serializer = post_serializer @@ -684,6 +717,42 @@ class SerializerTest < ActiveModel::TestCase }, hash.as_json) end + def test_embed_id_for_has_one_overriding_associated_id + author_serializer = Class.new(ActiveModel::Serializer) do + def id + "OMG" + end + end + + serializer_class = Class.new(ActiveModel::Serializer) do + embed :ids + root :post + + attributes :title, :body + has_one :author, :serializer => author_serializer + end + + post_class = Class.new(Model) do + attr_accessor :author + end + + author_class = Class.new(Model) + + post = post_class.new(:title => "New Post", :body => "It's a new post!") + author = author_class.new(:id => 5) + post.author = author + + hash = serializer_class.new(post) + + assert_equal({ + :post => { + :title => "New Post", + :body => "It's a new post!", + :author_id => "OMG" + } + }, hash.as_json) + end + def test_embed_objects_for_has_one author_serializer = Class.new(ActiveModel::Serializer) do attributes :id, :name