Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 4 additions & 0 deletions lib/active_model/serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,10 @@ def include!(name, options={})

if association.embed_in_root? && hash.nil?
raise IncludeError.new(self.class, association.name)
elsif association.embed_in_root? and association.instance_of? Association::HasMany and association.polymorphic?
association.roots.each do |root|
merge_association hash, root, association.serializables, unique_values
end
elsif association.embed_in_root? && association.embeddable?
merge_association hash, association.root, association.serializables, unique_values
end
Expand Down
52 changes: 48 additions & 4 deletions lib/active_model/serializer/associations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,21 @@ def find_serializable(object)
end

class HasMany < Association #:nodoc:
def initialize(name, options={}, serializer_options={})
super
@polymorphic = options[:polymorphic]
end

def root
options[:root] || name
end

def roots
object.map do |item|
pluralized_polymorphic_key_for_item(item)
end
end

def id_key
"#{name.to_s.singularize}_ids".to_sym
end
Expand All @@ -88,20 +99,53 @@ def serializables

def serialize
object.map do |item|
find_serializable(item).serializable_hash
if polymorphic?
polymorphic_key = polymorphic_key_for_item(item)

{
:type => polymorphic_key,
polymorphic_key => find_serializable(item).serializable_hash
}
else
find_serializable(item).serializable_hash
end
end
end

def serialize_ids
object.map do |item|
serializer = find_serializable(item)
if serializer.respond_to?(embed_key)
serializer.send(embed_key)
id = if serializer.respond_to?(embed_key)
serializer.send(embed_key)
else
item.read_attribute_for_serialization(embed_key)
end

if polymorphic?
polymorphic_key = polymorphic_key_for_item(item)

{
type: polymorphic_key,
id: id
}
else
item.read_attribute_for_serialization(embed_key)
id
end
end
end

attr_reader :polymorphic
alias polymorphic? polymorphic

private

def polymorphic_key_for_item(item)
item.class.to_s.underscore.to_sym
end

def pluralized_polymorphic_key_for_item(item)
item.class.to_s.pluralize.underscore.to_sym
end
end

class HasOne < Association #:nodoc:
Expand Down
46 changes: 46 additions & 0 deletions test/serializer_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1124,6 +1124,52 @@ def self.to_s
}, actual)
end

def tests_can_handle_polymorphic_has_many_associations
email_serializer = Class.new(ActiveModel::Serializer) do
attributes :subject, :body, :id
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
root :attachment
attributes :name, :url
embed :ids, include: true
has_many :attachables, polymorphic: true
end

email = email_class.new id: 1, subject: 'foo', body: 'bar'

attachment = AttachmentWithMany.new name: 'logo.png', url: 'http://example.com/logo.png', attachables: [ email ]

actual = attachment_serializer.new(attachment, {}).as_json

assert_equal({
:attachment => {
:name => 'logo.png',
:url => 'http://example.com/logo.png',
:attachable_ids => [{
:type => :email,
:id => 1
}]
},

:emails => [{
:id => 1,
:subject => "foo",
:body => "bar"
}]
}, actual)
end

def test_can_handle_polymoprhic_ids
email_serializer = Class.new(ActiveModel::Serializer) do
attributes :subject, :body
Expand Down
14 changes: 14 additions & 0 deletions test/test_fakes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -200,3 +200,17 @@ def edible
@attributes[:edible]
end
end

class AttachmentWithMany < Model
def attachables
@attributes[:attachables]
end

def readable
@attributes[:readable]
end

def edible
@attributes[:edible]
end
end