Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
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.
  • Loading branch information
markquezada committed Jan 7, 2015
commit d00561389ab38a128386be2d7415f0aa6358c0f0
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
5 changes: 3 additions & 2 deletions lib/active_model/array_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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

Expand Down
13 changes: 13 additions & 0 deletions lib/active_model/polymorphic_array_serializer.rb
Original file line number Diff line number Diff line change
@@ -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
18 changes: 15 additions & 3 deletions lib/active_model/serializer/association.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
4 changes: 3 additions & 1 deletion lib/active_model/serializer/association/has_many.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require 'active_model/polymorphic_array_serializer'

module ActiveModel
class Serializer
class Association
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion lib/active_model/serializer/association/has_one.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@ def build_serializer(object, options = {})
end
end
end
end
end