Skip to content

Commit 85658c0

Browse files
committed
Add better serialization_scope tests; uncover bug
1 parent 26b089c commit 85658c0

File tree

2 files changed

+195
-35
lines changed

2 files changed

+195
-35
lines changed

lib/active_model/serializer.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ def self._serializer_instance_method_defined?(name)
9696
_serializer_instance_methods.include?(name)
9797
end
9898

99+
# TODO: Fix load-order failures when different serializer instances define different
100+
# scope methods
99101
def self._serializer_instance_methods
100102
@_serializer_instance_methods ||= (public_instance_methods - Object.public_instance_methods).to_set
101103
end
Lines changed: 193 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,221 @@
11
require 'test_helper'
2-
require 'pathname'
32

4-
class DefaultScopeNameTest < ActionController::TestCase
5-
class UserSerializer < ActiveModel::Serializer
3+
module SerializationScopeTesting
4+
class User < ActiveModelSerializers::Model
5+
attr_accessor :id, :name, :admin
66
def admin?
7-
current_user.admin
7+
admin
88
end
9-
attributes :admin?
109
end
10+
class Comment < ActiveModelSerializers::Model
11+
attr_accessor :id, :body
12+
end
13+
class Post < ActiveModelSerializers::Model
14+
attr_accessor :id, :title, :body, :comments
15+
end
16+
class PostSerializer < ActiveModel::Serializer
17+
attributes :id, :title, :body, :comments
1118

12-
class UserTestController < ActionController::Base
13-
protect_from_forgery
14-
15-
before_action { request.format = :json }
19+
def body
20+
"The 'scope' is the 'current_user': #{scope == current_user}"
21+
end
1622

17-
def current_user
18-
User.new(id: 1, name: 'Pete', admin: false)
23+
def comments
24+
if current_user.admin?
25+
[Comment.new(id: 1, body: 'Admin')]
26+
else
27+
[Comment.new(id: 2, body: 'Scoped')]
28+
end
1929
end
2030

21-
def render_new_user
22-
render json: User.new(id: 1, name: 'Pete', admin: false), serializer: UserSerializer, adapter: :json_api
31+
def json_key
32+
'post'
2333
end
2434
end
35+
class PostTestController < ActionController::Base
36+
attr_accessor :current_user
37+
def render_post_by_non_admin
38+
self.current_user = User.new(id: 3, name: 'Pete', admin: false)
39+
render json: new_post, serializer: serializer, adapter: :json
40+
end
2541

26-
tests UserTestController
42+
def render_post_by_admin
43+
self.current_user = User.new(id: 3, name: 'Pete', admin: true)
44+
render json: new_post, serializer: serializer, adapter: :json
45+
end
46+
47+
private
2748

28-
def test_default_scope_name
29-
get :render_new_user
30-
assert_equal '{"data":{"id":"1","type":"users","attributes":{"admin?":false}}}', @response.body
49+
def new_post
50+
Post.new(id: 4, title: 'Title')
51+
end
52+
53+
def serializer
54+
PostSerializer
55+
end
3156
end
32-
end
57+
class PostViewContextSerializer < PostSerializer
58+
def body
59+
"The 'scope' is the 'view_context': #{scope == view_context}"
60+
end
3361

34-
class SerializationScopeNameTest < ActionController::TestCase
35-
class AdminUserSerializer < ActiveModel::Serializer
36-
def admin?
37-
current_admin.admin
62+
def comments
63+
if view_context.controller.current_user.admin?
64+
[Comment.new(id: 1, body: 'Admin')]
65+
else
66+
[Comment.new(id: 2, body: 'Scoped')]
67+
end
68+
end
69+
end
70+
class DefaultScopeTest < ActionController::TestCase
71+
tests PostTestController
72+
73+
def test_default_serialization_scope
74+
assert_equal :current_user, @controller._serialization_scope
75+
end
76+
77+
def test_default_serialization_scope_object
78+
assert_equal @controller.current_user, @controller.serialization_scope
79+
end
80+
81+
def test_default_scope_non_admin
82+
get :render_post_by_non_admin
83+
expected_json = {
84+
post: {
85+
id: 4,
86+
title: 'Title',
87+
body: "The 'scope' is the 'current_user': true",
88+
comments: [
89+
{ id: 2, body: 'Scoped' }
90+
]
91+
}
92+
}.to_json
93+
assert_equal expected_json, @response.body
94+
end
95+
96+
def test_default_scope_admin
97+
get :render_post_by_admin
98+
expected_json = {
99+
post: {
100+
id: 4,
101+
title: 'Title',
102+
body: "The 'scope' is the 'current_user': true",
103+
comments: [
104+
{ id: 1, body: 'Admin' }
105+
]
106+
}
107+
}.to_json
108+
assert_equal expected_json, @response.body
38109
end
39-
attributes :admin?
40110
end
111+
class SerializationScopeTest < ActionController::TestCase
112+
class PostViewContextTestController < PostTestController
113+
serialization_scope :view_context
114+
115+
private
116+
117+
def serializer
118+
PostViewContextSerializer
119+
end
120+
end
121+
tests PostViewContextTestController
41122

42-
class AdminUserTestController < ActionController::Base
43-
protect_from_forgery
123+
def test_defined_serialization_scope
124+
assert_equal :view_context, @controller._serialization_scope
125+
end
44126

45-
serialization_scope :current_admin
46-
before_action { request.format = :json }
127+
def test_defined_serialization_scope_object
128+
assert_equal @controller.view_context.class, @controller.serialization_scope.class
129+
end
47130

48-
def current_admin
49-
User.new(id: 2, name: 'Bob', admin: true)
131+
def test_serialization_scope_non_admin
132+
get :render_post_by_non_admin
133+
expected_json = {
134+
post: {
135+
id: 4,
136+
title: 'Title',
137+
body: "The 'scope' is the 'view_context': true",
138+
comments: [
139+
{ id: 2, body: 'Scoped' }
140+
]
141+
}
142+
}.to_json
143+
assert_equal expected_json, @response.body
50144
end
51145

52-
def render_new_user
53-
render json: User.new(id: 1, name: 'Pete', admin: false), serializer: AdminUserSerializer, adapter: :json_api
146+
def test_serialization_scope_admin
147+
get :render_post_by_admin
148+
expected_json = {
149+
post: {
150+
id: 4,
151+
title: 'Title',
152+
body: "The 'scope' is the 'view_context': true",
153+
comments: [
154+
{ id: 1, body: 'Admin' }
155+
]
156+
}
157+
}.to_json
158+
assert_equal expected_json, @response.body
54159
end
55160
end
161+
class NilSerializationScopeTest < ActionController::TestCase
162+
class PostViewContextTestController < ActionController::Base
163+
serialization_scope nil
164+
165+
attr_accessor :current_user
166+
167+
def render_post_with_no_scope
168+
self.current_user = User.new(id: 3, name: 'Pete', admin: false)
169+
render json: new_post, serializer: PostSerializer, adapter: :json
170+
end
56171

57-
tests AdminUserTestController
172+
# TODO: run test when
173+
# global state in Serializer._serializer_instance_methods is fixed
174+
# def render_post_with_passed_in_scope
175+
# self.current_user = User.new(id: 3, name: 'Pete', admin: false)
176+
# render json: new_post, serializer: PostSerializer, adapter: :json, scope: current_user, scope_name: :current_user
177+
# end
178+
179+
private
180+
181+
def new_post
182+
Post.new(id: 4, title: 'Title')
183+
end
184+
end
185+
tests PostViewContextTestController
186+
187+
def test_nil_serialization_scope
188+
assert_nil @controller._serialization_scope
189+
end
190+
191+
def test_nil_serialization_scope_object
192+
assert_nil @controller.serialization_scope
193+
end
194+
195+
# TODO: change to NoMethodError and match 'admin?' when the
196+
# global state in Serializer._serializer_instance_methods is fixed
197+
def test_nil_scope
198+
exception = assert_raises(NameError) do
199+
get :render_post_with_no_scope
200+
end
201+
assert_match(/admin|current_user/, exception.message)
202+
end
58203

59-
def test_override_scope_name_with_controller
60-
get :render_new_user
61-
assert_equal '{"data":{"id":"1","type":"users","attributes":{"admin?":true}}}', @response.body
204+
# TODO: run test when
205+
# global state in Serializer._serializer_instance_methods is fixed
206+
# def test_nil_scope_passed_in_current_user
207+
# get :render_post_with_passed_in_scope
208+
# expected_json = {
209+
# post: {
210+
# id: 4,
211+
# title: 'Title',
212+
# body: "The 'scope' is the 'current_user': true",
213+
# comments: [
214+
# { id: 2, body: 'Scoped' }
215+
# ]
216+
# }
217+
# }.to_json
218+
# assert_equal expected_json, @response.body
219+
# end
62220
end
63221
end

0 commit comments

Comments
 (0)