Skip to content

Commit bbed128

Browse files
author
cgmckeever
committed
adds polymorphic option to association definition which includes association type in serializer
regen gemlock regen gemlock better variable naming rubocop fixes adds to changelog adds empty relationship and has_many polymorph tests indent test cleaning -rubocop rubocop rubocop rubocop changelog remove silly .DS fix roque failure fix
1 parent 6c321cd commit bbed128

File tree

6 files changed

+159
-14
lines changed

6 files changed

+159
-14
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Features:
1616

1717
Fixes:
1818
- [#1700](https://github.com/rails-api/active_model_serializers/pull/1700) Support pagination link for Kaminari when no data is returned. (@iamnader)
19+
- [#1726](https://github.com/rails-api/active_model_serializers/pull/1726) Adds polymorphic option to association definition which includes association type/nesting in serializer (@cgmckeever)
1920

2021
Misc:
2122
- [#1673](https://github.com/rails-api/active_model_serializers/pull/1673) Adds "How to" guide on using AMS with POROs (@DrSayre)

docs/general/serializers.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ Where:
5252
- `if:`
5353
- `unless:`
5454
- `virtual_value:`
55+
- `polymorphic:` defines if polymorphic relation type should be nested in serialized association.
5556
- optional: `&block` is a context that returns the association's attributes.
5657
- prevents `association_name` method from being called.
5758
- return value of block is used as the association value.

lib/active_model_serializers/adapter/attributes.rb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,14 @@ def relationship_value_for(association, options)
4545
return unless association.serializer && association.serializer.object
4646

4747
opts = instance_options.merge(include: @include_tree[association.key])
48-
Attributes.new(association.serializer, opts).serializable_hash(options)
48+
relationship_value = Attributes.new(association.serializer, opts).serializable_hash(options)
49+
50+
if association.options[:polymorphic] && relationship_value
51+
polymorphic_type = association.serializer.object.class.name.underscore
52+
relationship_value = { type: polymorphic_type, polymorphic_type.to_sym => relationship_value }
53+
end
54+
55+
relationship_value
4956
end
5057

5158
# Set @cached_attributes

test/adapter/polymorphic_test.rb

Lines changed: 111 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,17 @@ class PolymorphicTest < ActiveSupport::TestCase
88
@employee = Employee.new(id: 42, name: 'Zoop Zoopler', email: '[email protected]')
99
@picture = @employee.pictures.new(id: 1, title: 'headshot-1.jpg')
1010
@picture.imageable = @employee
11+
end
12+
13+
def serialization(resource, adapter = :attributes)
14+
serializable(resource, adapter: adapter, serializer: PolymorphicBelongsToSerializer).as_json
15+
end
1116

12-
@attributes_serialization = serializable(@picture, serializer: PolymorphicBelongsToSerializer) # uses default adapter: attributes
13-
@json_serialization = serializable(@picture, adapter: :json, serializer: PolymorphicBelongsToSerializer)
14-
@json_api_serialization = serializable(@picture, adapter: :json_api, serializer: PolymorphicBelongsToSerializer)
17+
def tag_serialization(adapter = :attributes)
18+
tag = PolyTag.new(id: 1, phrase: 'foo')
19+
tag.object_tags << ObjectTag.new(id: 1, poly_tag_id: 1, taggable: @employee)
20+
tag.object_tags << ObjectTag.new(id: 5, poly_tag_id: 1, taggable: @picture)
21+
serializable(tag, adapter: adapter, serializer: PolymorphicTagSerializer, include: '*.*').as_json
1522
end
1623

1724
def test_attributes_serialization
@@ -20,31 +27,123 @@ def test_attributes_serialization
2027
id: 1,
2128
title: 'headshot-1.jpg',
2229
imageable: {
23-
id: 42,
24-
name: 'Zoop Zoopler'
30+
type: 'employee',
31+
employee: {
32+
id: 42,
33+
name: 'Zoop Zoopler'
34+
}
2535
}
2636
}
2737

28-
assert_equal(expected, @attributes_serialization.as_json)
38+
assert_equal(expected, serialization(@picture))
2939
end
3040

31-
def test_json_serializer
41+
def test_attributes_serialization_without_polymorphic_association
42+
expected =
43+
{
44+
id: 2,
45+
title: 'headshot-2.jpg',
46+
imageable: nil
47+
}
48+
49+
simple_picture = Picture.new(id: 2, title: 'headshot-2.jpg')
50+
assert_equal(expected, serialization(simple_picture))
51+
end
52+
53+
def test_attributes_serialization_with_polymorphic_has_many
54+
expected =
55+
{
56+
id: 1,
57+
phrase: 'foo',
58+
object_tags: [
59+
{
60+
id: 1,
61+
taggable: {
62+
type: 'employee',
63+
employee: {
64+
id: 42
65+
}
66+
}
67+
},
68+
{
69+
id: 5,
70+
taggable: {
71+
type: 'picture',
72+
picture: {
73+
id: 1
74+
}
75+
}
76+
}
77+
]
78+
}
79+
assert_equal(expected, tag_serialization)
80+
end
81+
82+
def test_json_serialization
3283
expected =
3384
{
3485
picture: {
3586
id: 1,
3687
title: 'headshot-1.jpg',
3788
imageable: {
38-
id: 42,
39-
name: 'Zoop Zoopler'
89+
type: 'employee',
90+
employee: {
91+
id: 42,
92+
name: 'Zoop Zoopler'
93+
}
4094
}
4195
}
4296
}
4397

44-
assert_equal(expected, @json_serialization.as_json)
98+
assert_equal(expected, serialization(@picture, :json))
99+
end
100+
101+
def test_json_serialization_without_polymorphic_association
102+
expected =
103+
{
104+
picture: {
105+
id: 2,
106+
title: 'headshot-2.jpg',
107+
imageable: nil
108+
}
109+
}
110+
111+
simple_picture = Picture.new(id: 2, title: 'headshot-2.jpg')
112+
assert_equal(expected, serialization(simple_picture, :json))
113+
end
114+
115+
def test_json_serialization_with_polymorphic_has_many
116+
expected =
117+
{
118+
poly_tag: {
119+
id: 1,
120+
phrase: 'foo',
121+
object_tags: [
122+
{
123+
id: 1,
124+
taggable: {
125+
type: 'employee',
126+
employee: {
127+
id: 42
128+
}
129+
}
130+
},
131+
{
132+
id: 5,
133+
taggable: {
134+
type: 'picture',
135+
picture: {
136+
id: 1
137+
}
138+
}
139+
}
140+
]
141+
}
142+
}
143+
assert_equal(expected, tag_serialization(:json))
45144
end
46145

47-
def test_json_api_serializer
146+
def test_json_api_serialization
48147
expected =
49148
{
50149
data: {
@@ -64,7 +163,7 @@ def test_json_api_serializer
64163
}
65164
}
66165

67-
assert_equal(expected, @json_api_serialization.as_json)
166+
assert_equal(expected, serialization(@picture, :json_api))
68167
end
69168
end
70169
end

test/fixtures/active_record.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,16 @@
2424
t.string :email
2525
t.timestamp null: false
2626
end
27+
create_table :object_tags, force: true do |t|
28+
t.string :poly_tag_id
29+
t.string :taggable_type
30+
t.string :taggable_id
31+
t.timestamp null: false
32+
end
33+
create_table :poly_tags, force: true do |t|
34+
t.string :phrase
35+
t.timestamp null: false
36+
end
2737
create_table :pictures, force: true do |t|
2838
t.string :title
2939
t.string :imageable_type

test/fixtures/poro.rb

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,21 @@ def cache_key
7070

7171
class Employee < ActiveRecord::Base
7272
has_many :pictures, as: :imageable
73+
has_many :object_tags, as: :taggable
74+
end
75+
76+
class ObjectTag < ActiveRecord::Base
77+
belongs_to :poly_tag
78+
belongs_to :taggable, polymorphic: true
7379
end
7480

7581
class Picture < ActiveRecord::Base
7682
belongs_to :imageable, polymorphic: true
83+
has_many :object_tags, as: :taggable
84+
end
85+
86+
class PolyTag < ActiveRecord::Base
87+
has_many :object_tags
7788
end
7889

7990
module Spam; end
@@ -245,7 +256,23 @@ def maker
245256
PolymorphicBelongsToSerializer = Class.new(ActiveModel::Serializer) do
246257
attributes :id, :title
247258

248-
has_one :imageable, serializer: PolymorphicHasManySerializer
259+
has_one :imageable, serializer: PolymorphicHasManySerializer, polymorphic: true
260+
end
261+
262+
PolymorphicSimpleSerializer = Class.new(ActiveModel::Serializer) do
263+
attributes :id
264+
end
265+
266+
PolymorphicObjectTagSerializer = Class.new(ActiveModel::Serializer) do
267+
attributes :id
268+
269+
has_many :taggable, serializer: PolymorphicSimpleSerializer, polymorphic: true
270+
end
271+
272+
PolymorphicTagSerializer = Class.new(ActiveModel::Serializer) do
273+
attributes :id, :phrase
274+
275+
has_many :object_tags, serializer: PolymorphicObjectTagSerializer
249276
end
250277

251278
Spam::UnrelatedLinkSerializer = Class.new(ActiveModel::Serializer) do

0 commit comments

Comments
 (0)