Skip to content

Commit b1fd433

Browse files
author
Yohan Robert
committed
Fix relationship behavior when using block
When using the relationships DSL with a block e.g. has_one :bio do link :self, "some_link" end the "data" field would be rendered with a nil value even though the bio is not nil. This happened because the block return value was set to nil but used as a value for the "data" field.
1 parent 2c41938 commit b1fd433

File tree

3 files changed

+182
-33
lines changed

3 files changed

+182
-33
lines changed

lib/active_model/serializer/reflection.rb

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,25 +42,30 @@ def initialize(*)
4242

4343
def link(name, value = nil, &block)
4444
@_links[name] = block || value
45-
nil
45+
:nil
4646
end
4747

4848
def meta(value = nil, &block)
4949
@_meta = block || value
50-
nil
50+
:nil
5151
end
5252

5353
def include_data(value = true)
5454
@_include_data = value
55-
nil
55+
:nil
5656
end
5757

5858
def value(serializer)
5959
@object = serializer.object
6060
@scope = serializer.scope
6161

6262
if block
63-
instance_eval(&block)
63+
block_value = instance_eval(&block)
64+
if block_value == :nil
65+
serializer.read_attribute_for_serialization(name)
66+
else
67+
block_value
68+
end
6469
else
6570
serializer.read_attribute_for_serialization(name)
6671
end

test/adapter/json_api/links_test.rb

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,6 @@ class LinkAuthorSerializer < ActiveModel::Serializer
1717
link :yet_another do
1818
"//example.com/resource/#{object.id}"
1919
end
20-
21-
has_many :posts do
22-
link :self do
23-
href '//example.com/link_author/relationships/posts'
24-
meta stuff: 'value'
25-
end
26-
link :related do
27-
href '//example.com/link_author/posts'
28-
meta count: object.posts.count
29-
end
30-
include_data false
31-
end
3220
end
3321

3422
def setup
@@ -91,23 +79,6 @@ def test_resource_links
9179
}
9280
assert_equal(expected, hash[:data][:links])
9381
end
94-
95-
def test_relationship_links
96-
hash = serializable(@author, adapter: :json_api).serializable_hash
97-
expected = {
98-
links: {
99-
self: {
100-
href: '//example.com/link_author/relationships/posts',
101-
meta: { stuff: 'value' }
102-
},
103-
related: {
104-
href: '//example.com/link_author/posts',
105-
meta: { count: 1 }
106-
}
107-
}
108-
}
109-
assert_equal(expected, hash[:data][:relationships][:posts])
110-
end
11182
end
11283
end
11384
end
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
require 'test_helper'
2+
3+
module ActiveModel
4+
class Serializer
5+
module Adapter
6+
class JsonApi
7+
class RelationshipTest < ActiveSupport::TestCase
8+
RelationshipAuthor = Class.new(::Model)
9+
class RelationshipAuthorSerializer < ActiveModel::Serializer
10+
has_one :bio do
11+
link :self, '//example.com/link_author/relationships/bio'
12+
end
13+
14+
has_one :profile do
15+
link :related do
16+
"//example.com/profiles/#{object.profile.id}"
17+
end
18+
end
19+
20+
has_many :locations do
21+
link :related do
22+
ids = object.locations.map!(&:id).join(',')
23+
href "//example.com/locations/#{ids}"
24+
end
25+
end
26+
27+
has_many :posts do
28+
link :related do
29+
ids = object.posts.map!(&:id).join(',')
30+
href "//example.com/posts/#{ids}"
31+
meta ids: ids
32+
end
33+
end
34+
35+
has_many :roles do
36+
meta count: object.posts.count
37+
end
38+
39+
has_one :blog do
40+
link :self, '//example.com/link_author/relationships/blog'
41+
include_data false
42+
end
43+
44+
belongs_to :reviewer do
45+
meta name: 'Dan Brown'
46+
include_data true
47+
end
48+
49+
has_many :likes do
50+
link :related do
51+
ids = object.likes.map!(&:id).join(',')
52+
href "//example.com/likes/#{ids}"
53+
meta ids: ids
54+
end
55+
meta liked: object.likes.any?
56+
end
57+
end
58+
59+
def setup
60+
@post = Post.new(id: 1337, comments: [], author: nil)
61+
@blog = Blog.new(id: 1337, name: 'extra')
62+
@bio = Bio.new(id: 1337)
63+
@like = Like.new(id: 1337)
64+
@role = Role.new(id: 1337)
65+
@profile = Profile.new(id: 1337)
66+
@location = Location.new(id: 1337)
67+
@reviewer = Author.new(id: 1337)
68+
@author = RelationshipAuthor.new(
69+
id: 1337,
70+
posts: [@post],
71+
blog: @blog,
72+
reviewer: @reviewer,
73+
bio: @bio,
74+
likes: [@like],
75+
roles: [@role],
76+
locations: [@location],
77+
profile: @profile
78+
)
79+
end
80+
81+
def test_relationship_simple_link
82+
hash = serializable(@author, adapter: :json_api).serializable_hash
83+
expected = {
84+
data: {
85+
id: '1337',
86+
type: 'bios'
87+
},
88+
links: {
89+
self: '//example.com/link_author/relationships/bio'
90+
}
91+
}
92+
assert_equal(expected, hash[:data][:relationships][:bio])
93+
end
94+
95+
def test_relationship_block_link
96+
hash = serializable(@author, adapter: :json_api).serializable_hash
97+
expected = {
98+
data: { id: '1337', type: 'profiles' },
99+
links: { related: '//example.com/profiles/1337' }
100+
}
101+
assert_equal(expected, hash[:data][:relationships][:profile])
102+
end
103+
104+
def test_relationship_block_link_href
105+
hash = serializable(@author, adapter: :json_api).serializable_hash
106+
expected = {
107+
data: [{ id: '1337', type: 'locations' }],
108+
links: {
109+
related: { href: '//example.com/locations/1337' }
110+
}
111+
}
112+
assert_equal(expected, hash[:data][:relationships][:locations])
113+
end
114+
115+
def test_relationship_block_link_meta
116+
hash = serializable(@author, adapter: :json_api).serializable_hash
117+
expected = {
118+
data: [{ id: '1337', type: 'posts' }],
119+
links: {
120+
related: {
121+
href: '//example.com/posts/1337',
122+
meta: { ids: '1337' }
123+
}
124+
}
125+
}
126+
assert_equal(expected, hash[:data][:relationships][:posts])
127+
end
128+
129+
def test_relationship_meta
130+
hash = serializable(@author, adapter: :json_api).serializable_hash
131+
expected = {
132+
data: [{ id: '1337', type: 'roles' }],
133+
meta: { count: 1 }
134+
}
135+
assert_equal(expected, hash[:data][:relationships][:roles])
136+
end
137+
138+
def test_relationship_not_including_data
139+
hash = serializable(@author, adapter: :json_api).serializable_hash
140+
expected = {
141+
links: { self: '//example.com/link_author/relationships/blog' }
142+
}
143+
assert_equal(expected, hash[:data][:relationships][:blog])
144+
end
145+
146+
def test_relationship_including_data_explicit
147+
hash = serializable(@author, adapter: :json_api).serializable_hash
148+
expected = {
149+
data: { id: '1337', type: 'authors' },
150+
meta: { name: 'Dan Brown' }
151+
}
152+
assert_equal(expected, hash[:data][:relationships][:reviewer])
153+
end
154+
155+
def test_relationship_with_everything
156+
hash = serializable(@author, adapter: :json_api).serializable_hash
157+
expected = {
158+
data: [{ id: '1337', type: 'likes' }],
159+
links: {
160+
related: {
161+
href: '//example.com/likes/1337',
162+
meta: { ids: '1337' }
163+
}
164+
},
165+
meta: { liked: true }
166+
}
167+
assert_equal(expected, hash[:data][:relationships][:likes])
168+
end
169+
end
170+
end
171+
end
172+
end
173+
end

0 commit comments

Comments
 (0)