From b78806c6f423681dc33caa5b0b2f2331ecac02fd Mon Sep 17 00:00:00 2001 From: Mark Quezada Date: Tue, 6 Jan 2015 14:38:59 -1000 Subject: [PATCH 1/5] Don't use array serializer when rendering a hash --- lib/action_controller/serialization.rb | 4 ++-- lib/active_model/serializer.rb | 2 +- .../action_controller/serialization_test.rb | 16 ++++++++++++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/action_controller/serialization.rb b/lib/action_controller/serialization.rb index df23aa956..9a76ebc33 100644 --- a/lib/action_controller/serialization.rb +++ b/lib/action_controller/serialization.rb @@ -87,8 +87,8 @@ def build_json_serializer(resource, options = {}) if serializer = options.fetch(:serializer, default_serializer(resource)) options[:scope] = serialization_scope unless options.has_key?(:scope) - if resource.respond_to?(:each) - options[:resource_name] = controller_name + if resource.respond_to?(:each) && !resource.is_a?(Hash) + options[:resource_name] = controller_name options[:namespace] = namespace_for_serializer if namespace_for_serializer end diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 7a6ee7ca2..01b439e72 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -56,7 +56,7 @@ def format_keys(format) attr_reader :key_format def serializer_for(resource, options = {}) - if resource.respond_to?(:each) + if resource.respond_to?(:each) && !resource.is_a?(Hash) if Object.constants.include?(:ArraySerializer) ::ArraySerializer else diff --git a/test/integration/action_controller/serialization_test.rb b/test/integration/action_controller/serialization_test.rb index e3ec71b34..d5ae5434d 100644 --- a/test/integration/action_controller/serialization_test.rb +++ b/test/integration/action_controller/serialization_test.rb @@ -299,5 +299,21 @@ def test_render_array assert_equal '{"my":[{"name":"Name 1"}]}', @response.body end end + + class SimpleHashObjectTest < ActionController::TestCase + class MyController < ActionController::Base + def render_hash + render json: { name: 'Name 1', description: 'Description 1', comments: 'Comments 1' } + end + end + + tests MyController + + def test_render_hash + get :render_hash + assert_equal 'application/json', @response.content_type + assert_equal '{"name":"Name 1","description":"Description 1","comments":"Comments 1"}', @response.body + end + end end end From d00561389ab38a128386be2d7415f0aa6358c0f0 Mon Sep 17 00:00:00 2001 From: Mark Quezada Date: Tue, 6 Jan 2015 13:25:05 -1000 Subject: [PATCH 2/5] WIP: Add ability to define polymorphic serializers This is done by adding a hash of key/value pairs matching a class type to its serializer. It allows the ability to use something other than the default serializer for polymorphic relationships. --- README.md | 23 +++++++++++++++++++ lib/active_model/array_serializer.rb | 5 ++-- .../polymorphic_array_serializer.rb | 13 +++++++++++ lib/active_model/serializer/association.rb | 18 ++++++++++++--- .../serializer/association/has_many.rb | 4 +++- .../serializer/association/has_one.rb | 2 +- 6 files changed, 58 insertions(+), 7 deletions(-) create mode 100644 lib/active_model/polymorphic_array_serializer.rb diff --git a/README.md b/README.md index 9c7fd6fd2..04a88a6ec 100644 --- a/README.md +++ b/README.md @@ -805,6 +805,29 @@ end } ``` +You can also define serializers for a polymorphic relationship like so: + + +```ruby +class PostSerializer < ActiveModel::Serializer + attributes :id, :title + has_many :attachments, polymorphic: true, each_serializer: { video: SpecialVideoSerializer, audio: AudioSummarySerializer } +end + +``` + +Or, for `has_one` relationships: + +```ruby +class PostSerializer < ActiveModel::Serializer + attributes :id, :title + has_one :attachment, polymorphic: true, serializer: { video: SpecialVideoSerializer, audio: AudioSummarySerializer } +end +``` + +In this case, if the `attachment` is a Video object, instead of using the +standard VideoSerializer, the SpecialVideoSerializer will be used. Any other +objects not defined by the hash will use the default serializers. ## Customizing Scope diff --git a/lib/active_model/array_serializer.rb b/lib/active_model/array_serializer.rb index e819de3df..2bcd8e574 100644 --- a/lib/active_model/array_serializer.rb +++ b/lib/active_model/array_serializer.rb @@ -18,12 +18,13 @@ def initialize(object, options={}) @polymorphic = options.fetch(:polymorphic, false) @meta_key = options[:meta_key] || :meta @meta = options[@meta_key] - @each_serializer = options[:each_serializer] @resource_name = options[:resource_name] @only = options[:only] ? Array(options[:only]) : nil @except = options[:except] ? Array(options[:except]) : nil @namespace = options[:namespace] @key_format = options[:key_format] || options[:each_serializer].try(:key_format) + @each_serializer = options[:each_serializer] + @each_serializer_from_options = @each_serializer.is_a?(Hash) ? nil : @each_serializer end attr_accessor :object, :scope, :root, :meta_key, :meta, :key_format @@ -34,7 +35,7 @@ def json_key end def serializer_for(item) - serializer_class = @each_serializer || Serializer.serializer_for(item, namespace: @namespace) || DefaultSerializer + serializer_class = @each_serializer_from_options || Serializer.serializer_for(item, namespace: @namespace) || DefaultSerializer serializer_class.new(item, scope: scope, key_format: key_format, only: @only, except: @except, polymorphic: @polymorphic, namespace: @namespace) end diff --git a/lib/active_model/polymorphic_array_serializer.rb b/lib/active_model/polymorphic_array_serializer.rb new file mode 100644 index 000000000..1e20add0b --- /dev/null +++ b/lib/active_model/polymorphic_array_serializer.rb @@ -0,0 +1,13 @@ +module ActiveModel + class PolymorphicArraySerializer < ArraySerializer + def serializer_for(item) + if @each_serializer.is_a?(Hash) && polymorphic? + polymorphic_object_key = item.class.name.underscore.to_sym + return nil unless @each_serializer.has_key?(polymorphic_object_key) + @each_serializer[polymorphic_object_key] + else + super + end + end + end +end diff --git a/lib/active_model/serializer/association.rb b/lib/active_model/serializer/association.rb index 5ea22056d..781e46acf 100644 --- a/lib/active_model/serializer/association.rb +++ b/lib/active_model/serializer/association.rb @@ -24,8 +24,14 @@ def initialize(name, options={}) @embed_in_root_key = options.fetch(:embed_in_root_key) { CONFIG.embed_in_root_key } @embed_namespace = options.fetch(:embed_namespace) { CONFIG.embed_namespace } - serializer = @options[:serializer] - @serializer_from_options = serializer.is_a?(String) ? serializer.constantize : serializer + @serializer = options[:serializer] + @serializer_from_options = if @serializer.is_a?(Hash) + nil + elsif @serializer.is_a?(String) + @serializer.constantize + else + @serializer + end end attr_reader :name, :embed_ids, :embed_objects, :polymorphic @@ -43,7 +49,13 @@ def embed=(embed) end def serializer_from_object(object, options = {}) - Serializer.serializer_for(object, options) + if @serializer.is_a?(Hash) && polymorphic? + polymorphic_object_key = object.class.name.underscore.to_sym + return nil unless @serializer.has_key?(polymorphic_object_key) + @serializer[polymorphic_object_key] + else + Serializer.serializer_for(object, options) + end end def default_serializer diff --git a/lib/active_model/serializer/association/has_many.rb b/lib/active_model/serializer/association/has_many.rb index f05e92181..da49e3213 100644 --- a/lib/active_model/serializer/association/has_many.rb +++ b/lib/active_model/serializer/association/has_many.rb @@ -1,3 +1,5 @@ +require 'active_model/polymorphic_array_serializer' + module ActiveModel class Serializer class Association @@ -13,7 +15,7 @@ def initialize(name, *args) def serializer_class(object, _) if use_array_serializer? - ArraySerializer + polymorphic? ? PolymorphicArraySerializer : ArraySerializer else serializer_from_options end diff --git a/lib/active_model/serializer/association/has_one.rb b/lib/active_model/serializer/association/has_one.rb index 38c8b9bcb..e9763aa55 100644 --- a/lib/active_model/serializer/association/has_one.rb +++ b/lib/active_model/serializer/association/has_one.rb @@ -22,4 +22,4 @@ def build_serializer(object, options = {}) end end end -end \ No newline at end of file +end From 167583bbd6aac28d49591cc972adf79aa9ee67bc Mon Sep 17 00:00:00 2001 From: Jason Axelson Date: Thu, 30 Nov 2017 15:13:21 -1000 Subject: [PATCH 3/5] Pass through context through the array serializer (#1) * Pass through context through the array serializer * Add docs --- README.md | 15 +++++++++++++++ lib/active_model/array_serializer.rb | 3 ++- lib/active_model/serializer.rb | 2 +- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 04a88a6ec..2e447d5eb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,21 @@ [![Build Status](https://api.travis-ci.org/rails-api/active_model_serializers.png?branch=0-9-stable)](https://travis-ci.org/rails-api/active_model_serializers) [![Code Climate](https://codeclimate.com/github/rails-api/active_model_serializers.png)](https://codeclimate.com/github/rails-api/active_model_serializers) +## This Fork + +Adds polymorphic support for serializers + +Allows the the passed in `context` option to be passed through to a `has_many` +association (by modifying the `ArraySerializer`). This can be used by +specifying `:context` as a key when invoking the serializer, either via `.new` +or via `respond_with`/`to_json`. + +Context example: + + respond_with(:api, :v2, @event, serializer: ::API::V2::EventSerializer, context: { render_guest: true }) do |format| + # Render code + end + # ActiveModel::Serializers ## Purpose diff --git a/lib/active_model/array_serializer.rb b/lib/active_model/array_serializer.rb index 2bcd8e574..a5e143417 100644 --- a/lib/active_model/array_serializer.rb +++ b/lib/active_model/array_serializer.rb @@ -25,6 +25,7 @@ def initialize(object, options={}) @key_format = options[:key_format] || options[:each_serializer].try(:key_format) @each_serializer = options[:each_serializer] @each_serializer_from_options = @each_serializer.is_a?(Hash) ? nil : @each_serializer + @context = options[:context] end attr_accessor :object, :scope, :root, :meta_key, :meta, :key_format @@ -36,7 +37,7 @@ def json_key def serializer_for(item) serializer_class = @each_serializer_from_options || Serializer.serializer_for(item, namespace: @namespace) || DefaultSerializer - serializer_class.new(item, scope: scope, key_format: key_format, only: @only, except: @except, polymorphic: @polymorphic, namespace: @namespace) + serializer_class.new(item, scope: scope, key_format: key_format, only: @only, except: @except, polymorphic: @polymorphic, namespace: @namespace, context: @context) end def serializable_object(options={}) diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 01b439e72..79651c09a 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -230,7 +230,7 @@ def association_options_for_serializer(association) prefix = association.options[:prefix] namespace = association.options[:namespace] || @namespace || self.namespace - { scope: scope }.tap do |opts| + { scope: scope, context: context }.tap do |opts| opts[:namespace] = namespace if namespace opts[:prefix] = prefix if prefix end From 11a62bf8d20feaf4c3a29db98313175769e5de91 Mon Sep 17 00:00:00 2001 From: tom Date: Mon, 11 Nov 2024 14:07:10 +0800 Subject: [PATCH 4/5] fix error --- lib/action_controller/serialization.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/action_controller/serialization.rb b/lib/action_controller/serialization.rb index 9a76ebc33..4c840b518 100644 --- a/lib/action_controller/serialization.rb +++ b/lib/action_controller/serialization.rb @@ -60,7 +60,7 @@ def serialization_scope(scope) private def namespace_for_serializer - @namespace_for_serializer ||= self.class.parent unless self.class.parent == Object + @namespace_for_serializer ||= self.class.module_parent unless self.class.module_parent == Object end def default_serializer(resource) From 3dfe94587212156ac6197674877bc14e90a73c45 Mon Sep 17 00:00:00 2001 From: tom Date: Tue, 29 Jul 2025 14:08:54 +0800 Subject: [PATCH 5/5] try to fix Expected string default value for '--serializer'; got true (boolean) --- README.md | 5 ++--- .../generators/serializer/scaffold_controller_generator.rb | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2e447d5eb..a6fe7881c 100644 --- a/README.md +++ b/README.md @@ -250,7 +250,6 @@ end You can specify that serializers use the lower-camel key format at the config, class or instance level. ```ruby - ActiveModel::Serializer.setup do |config| config.key_format = :lower_camel end @@ -266,11 +265,11 @@ BlogSerializer.new(object, key_format: :lower_camel) You can specify that serializers use unsuffixed names as association keys by default. -`````ruby +```ruby ActiveModel::Serializer.setup do |config| config.default_key_type = :name end -```` +``` This will build association keys like `comments` or `author` instead of `comment_ids` or `author_id`. diff --git a/lib/active_model/serializer/generators/serializer/scaffold_controller_generator.rb b/lib/active_model/serializer/generators/serializer/scaffold_controller_generator.rb index 6647683a1..41f0ed13d 100644 --- a/lib/active_model/serializer/generators/serializer/scaffold_controller_generator.rb +++ b/lib/active_model/serializer/generators/serializer/scaffold_controller_generator.rb @@ -7,7 +7,7 @@ class ScaffoldControllerGenerator if Rails::VERSION::MAJOR >= 4 source_root File.expand_path('../templates', __FILE__) - hook_for :serializer, default: true + hook_for :serializer, default: true, type: :boolean end end end