active_model_serializers 0.5.2 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -66,6 +66,10 @@ class RenderJsonTest < ActionController::TestCase
66
66
  end
67
67
  end
68
68
 
69
+ class CustomArraySerializer < ActiveModel::ArraySerializer
70
+ self.root = "items"
71
+ end
72
+
69
73
  class TestController < ActionController::Base
70
74
  protect_from_forgery
71
75
 
@@ -127,13 +131,25 @@ class RenderJsonTest < ActionController::TestCase
127
131
  render :json => JsonSerializable.new, :options => true
128
132
  end
129
133
 
134
+ def render_json_with_serializer_and_scope_option
135
+ @current_user = Struct.new(:as_json).new(:current_user => true)
136
+ scope = Struct.new(:as_json).new(:current_user => false)
137
+ render :json => JsonSerializable.new, :scope => scope
138
+ end
139
+
130
140
  def render_json_with_serializer_api_but_without_serializer
131
141
  @current_user = Struct.new(:as_json).new(:current_user => true)
132
142
  render :json => JsonSerializable.new(true)
133
143
  end
134
144
 
145
+ # To specify a custom serializer for an object, use :serializer.
135
146
  def render_json_with_custom_serializer
136
- render :json => [], :serializer => CustomSerializer
147
+ render :json => Object.new, :serializer => CustomSerializer
148
+ end
149
+
150
+ # To specify a custom serializer for each item in the Array, use :each_serializer.
151
+ def render_json_array_with_custom_serializer
152
+ render :json => [Object.new], :each_serializer => CustomSerializer
137
153
  end
138
154
 
139
155
  def render_json_with_links
@@ -144,6 +160,14 @@ class RenderJsonTest < ActionController::TestCase
144
160
  render :json => [], :root => false
145
161
  end
146
162
 
163
+ def render_json_empty_array
164
+ render :json => []
165
+ end
166
+
167
+ def render_json_array_with_custom_array_serializer
168
+ render :json => [], :serializer => CustomArraySerializer
169
+ end
170
+
147
171
 
148
172
  private
149
173
  def default_serializer_options
@@ -190,7 +214,8 @@ class RenderJsonTest < ActionController::TestCase
190
214
  def test_render_json_with_callback
191
215
  get :render_json_hello_world_with_callback
192
216
  assert_equal 'alert({"hello":"world"})', @response.body
193
- assert_equal 'application/json', @response.content_type
217
+ # For JSONP, Rails 3 uses application/json, but Rails 4 uses text/javascript
218
+ assert_match %r(application/json|text/javascript), @response.content_type.to_s
194
219
  end
195
220
 
196
221
  def test_render_json_with_custom_content_type
@@ -241,6 +266,11 @@ class RenderJsonTest < ActionController::TestCase
241
266
  assert_match '"options":true', @response.body
242
267
  end
243
268
 
269
+ def test_render_json_with_serializer_and_scope_option
270
+ get :render_json_with_serializer_and_scope_option
271
+ assert_match '"scope":{"current_user":false}', @response.body
272
+ end
273
+
244
274
  def test_render_json_with_serializer_api_but_without_serializer
245
275
  get :render_json_with_serializer_api_but_without_serializer
246
276
  assert_match '{"serializable_object":true}', @response.body
@@ -251,6 +281,11 @@ class RenderJsonTest < ActionController::TestCase
251
281
  assert_match '{"hello":true}', @response.body
252
282
  end
253
283
 
284
+ def test_render_json_array_with_custom_serializer
285
+ get :render_json_array_with_custom_serializer
286
+ assert_match '{"test":[{"hello":true}]}', @response.body
287
+ end
288
+
254
289
  def test_render_json_with_links
255
290
  get :render_json_with_links
256
291
  assert_match '{"link":"http://www.nextangle.com/hypermedia"}', @response.body
@@ -260,4 +295,23 @@ class RenderJsonTest < ActionController::TestCase
260
295
  get :render_json_array_with_no_root
261
296
  assert_equal '[]', @response.body
262
297
  end
298
+
299
+ def test_render_json_empty_array
300
+ get :render_json_empty_array
301
+ assert_equal '{"test":[]}', @response.body
302
+ end
303
+
304
+ def test_render_json_empty_arry_with_array_serializer_root_false
305
+ ActiveModel::ArraySerializer.root = false
306
+ get :render_json_empty_array
307
+ assert_equal '[]', @response.body
308
+ ensure # teardown
309
+ ActiveModel::ArraySerializer.root = nil
310
+ end
311
+
312
+ def test_render_json_array_with_custom_array_serializer
313
+ get :render_json_array_with_custom_array_serializer
314
+ assert_equal '{"items":[]}', @response.body
315
+ end
316
+
263
317
  end
@@ -4,8 +4,27 @@ class RandomModel
4
4
  include ActiveModel::SerializerSupport
5
5
  end
6
6
 
7
+ class RandomModelCollection
8
+ include ActiveModel::ArraySerializerSupport
9
+ end
10
+
11
+ module ActiveRecord
12
+ class Relation
13
+ end
14
+ end
15
+
7
16
  class SerializerSupportTest < ActiveModel::TestCase
8
17
  test "it returns nil if no serializer exists" do
9
18
  assert_equal nil, RandomModel.new.active_model_serializer
10
19
  end
11
- end
20
+
21
+ test "it returns ArraySerializer for a collection" do
22
+ assert_equal ActiveModel::ArraySerializer, RandomModelCollection.new.active_model_serializer
23
+ end
24
+
25
+ test "it automatically includes array_serializer in active_record/relation" do
26
+ ActiveSupport.run_load_hooks(:active_record)
27
+ assert_equal ActiveModel::ArraySerializer, ActiveRecord::Relation.new.active_model_serializer
28
+ end
29
+ end
30
+
@@ -37,10 +37,11 @@ class SerializerTest < ActiveModel::TestCase
37
37
  def initialize(attributes)
38
38
  super(attributes)
39
39
  self.comments ||= []
40
+ self.comments_disabled = false
40
41
  self.author = nil
41
42
  end
42
43
 
43
- attr_accessor :comments, :author
44
+ attr_accessor :comments, :comments_disabled, :author
44
45
  def active_model_serializer; PostSerializer; end
45
46
  end
46
47
 
@@ -89,9 +90,9 @@ class SerializerTest < ActiveModel::TestCase
89
90
  end
90
91
  end
91
92
 
92
- class PostSerializer < ActiveModel::Serializer
93
- attributes :title, :body
94
- has_many :comments, :serializer => CommentSerializer
93
+ def test_scope_works_correct
94
+ serializer = ActiveModel::Serializer.new :foo, :scope => :bar
95
+ assert_equal serializer.scope, :bar
95
96
  end
96
97
 
97
98
  def test_attributes
@@ -138,6 +139,12 @@ class SerializerTest < ActiveModel::TestCase
138
139
  assert_equal({ :host => "test.local" }, user_serializer.url_options)
139
140
  end
140
141
 
142
+ def test_serializer_returns_empty_hash_without_url_options
143
+ user = User.new
144
+ user_serializer = UserSerializer.new(user)
145
+ assert_equal({}, user_serializer.url_options)
146
+ end
147
+
141
148
  def test_pretty_accessors
142
149
  user = User.new
143
150
  user.superuser = true
@@ -152,6 +159,11 @@ class SerializerTest < ActiveModel::TestCase
152
159
  }, hash)
153
160
  end
154
161
 
162
+ class PostSerializer < ActiveModel::Serializer
163
+ attributes :title, :body
164
+ has_many :comments, :serializer => CommentSerializer
165
+ end
166
+
155
167
  def test_has_many
156
168
  user = User.new
157
169
 
@@ -173,6 +185,104 @@ class SerializerTest < ActiveModel::TestCase
173
185
  }, post_serializer.as_json)
174
186
  end
175
187
 
188
+ class PostWithConditionalCommentsSerializer < ActiveModel::Serializer
189
+ root :post
190
+ attributes :title, :body
191
+ has_many :comments, :serializer => CommentSerializer
192
+
193
+ def include_associations!
194
+ include! :comments unless object.comments_disabled
195
+ end
196
+ end
197
+
198
+ def test_conditionally_included_associations
199
+ user = User.new
200
+
201
+ post = Post.new(:title => "New Post", :body => "Body of new post", :email => "tenderlove@tenderlove.com")
202
+ comments = [Comment.new(:title => "Comment1"), Comment.new(:title => "Comment2")]
203
+ post.comments = comments
204
+
205
+ post_serializer = PostWithConditionalCommentsSerializer.new(post, :scope => user)
206
+
207
+ # comments enabled
208
+ post.comments_disabled = false
209
+ assert_equal({
210
+ :post => {
211
+ :title => "New Post",
212
+ :body => "Body of new post",
213
+ :comments => [
214
+ { :title => "Comment1" },
215
+ { :title => "Comment2" }
216
+ ]
217
+ }
218
+ }, post_serializer.as_json)
219
+
220
+ # comments disabled
221
+ post.comments_disabled = true
222
+ assert_equal({
223
+ :post => {
224
+ :title => "New Post",
225
+ :body => "Body of new post"
226
+ }
227
+ }, post_serializer.as_json)
228
+ end
229
+
230
+ class PostWithMultipleConditionalsSerializer < ActiveModel::Serializer
231
+ root :post
232
+ attributes :title, :body, :author
233
+ has_many :comments, :serializer => CommentSerializer
234
+
235
+ def include_comments?
236
+ !object.comments_disabled
237
+ end
238
+
239
+ def include_author?
240
+ scope.super_user?
241
+ end
242
+ end
243
+
244
+ def test_conditionally_included_associations_and_attributes
245
+ user = User.new
246
+
247
+ post = Post.new(:title => "New Post", :body => "Body of new post", :author => 'Sausage King', :email => "tenderlove@tenderlove.com")
248
+ comments = [Comment.new(:title => "Comment1"), Comment.new(:title => "Comment2")]
249
+ post.comments = comments
250
+
251
+ post_serializer = PostWithMultipleConditionalsSerializer.new(post, :scope => user)
252
+
253
+ # comments enabled
254
+ post.comments_disabled = false
255
+ assert_equal({
256
+ :post => {
257
+ :title => "New Post",
258
+ :body => "Body of new post",
259
+ :comments => [
260
+ { :title => "Comment1" },
261
+ { :title => "Comment2" }
262
+ ]
263
+ }
264
+ }, post_serializer.as_json)
265
+
266
+ # comments disabled
267
+ post.comments_disabled = true
268
+ assert_equal({
269
+ :post => {
270
+ :title => "New Post",
271
+ :body => "Body of new post"
272
+ }
273
+ }, post_serializer.as_json)
274
+
275
+ # superuser - should see author
276
+ user.superuser = true
277
+ assert_equal({
278
+ :post => {
279
+ :title => "New Post",
280
+ :body => "Body of new post",
281
+ :author => "Sausage King"
282
+ }
283
+ }, post_serializer.as_json)
284
+ end
285
+
176
286
  class Blog < Model
177
287
  attr_accessor :author
178
288
  end
@@ -408,7 +518,41 @@ class SerializerTest < ActiveModel::TestCase
408
518
  hash = {:value => "something"}
409
519
  array = [hash]
410
520
  serializer = array.active_model_serializer.new(array, :root => :items)
411
- assert_equal({ :items => [ hash ]}, serializer.as_json)
521
+ assert_equal({ :items => [ hash.as_json ]}, serializer.as_json)
522
+ end
523
+
524
+ class CustomPostSerializer < ActiveModel::Serializer
525
+ attributes :title
526
+ end
527
+
528
+ def test_array_serializer_with_specified_seriailizer
529
+ post1 = Post.new(:title => "Post1", :author => "Author1", :id => 1)
530
+ post2 = Post.new(:title => "Post2", :author => "Author2", :id => 2)
531
+
532
+ array = [ post1, post2 ]
533
+
534
+ serializer = array.active_model_serializer.new array, :each_serializer => CustomPostSerializer
535
+
536
+ assert_equal([
537
+ { :title => "Post1" },
538
+ { :title => "Post2" }
539
+ ], serializer.as_json)
540
+ end
541
+
542
+ def test_sets_can_be_serialized
543
+ post1 = Post.new(:title => "Post1", :author => "Author1", :id => 1)
544
+ post2 = Post.new(:title => "Post2", :author => "Author2", :id => 2)
545
+
546
+ set = Set.new
547
+ set << post1
548
+ set << post2
549
+
550
+ serializer = set.active_model_serializer.new set, :each_serializer => CustomPostSerializer
551
+
552
+ as_json = serializer.as_json
553
+ assert_equal 2, as_json.size
554
+ assert as_json.include?({ :title => "Post1" })
555
+ assert as_json.include?({ :title => "Post2" })
412
556
  end
413
557
 
414
558
  class CustomBlog < Blog
@@ -890,4 +1034,358 @@ class SerializerTest < ActiveModel::TestCase
890
1034
  end
891
1035
  assert_equal ActiveModel::Serializer, loaded
892
1036
  end
1037
+
1038
+ def tests_query_attributes_strip_question_mark
1039
+ todo = Class.new do
1040
+ def overdue?
1041
+ true
1042
+ end
1043
+
1044
+ def read_attribute_for_serialization(name)
1045
+ send name
1046
+ end
1047
+ end
1048
+
1049
+ serializer = Class.new(ActiveModel::Serializer) do
1050
+ attribute :overdue?
1051
+ end
1052
+
1053
+ actual = serializer.new(todo.new).as_json
1054
+
1055
+ assert_equal({
1056
+ :overdue => true
1057
+ }, actual)
1058
+ end
1059
+
1060
+ def tests_query_attributes_allow_key_option
1061
+ todo = Class.new do
1062
+ def overdue?
1063
+ true
1064
+ end
1065
+
1066
+ def read_attribute_for_serialization(name)
1067
+ send name
1068
+ end
1069
+ end
1070
+
1071
+ serializer = Class.new(ActiveModel::Serializer) do
1072
+ attribute :overdue?, :key => :foo
1073
+ end
1074
+
1075
+ actual = serializer.new(todo.new).as_json
1076
+
1077
+ assert_equal({
1078
+ :foo => true
1079
+ }, actual)
1080
+ end
1081
+
1082
+ # Set up some classes for polymorphic testing
1083
+ class Attachment < Model
1084
+ def attachable
1085
+ @attributes[:attachable]
1086
+ end
1087
+
1088
+ def readable
1089
+ @attributes[:readable]
1090
+ end
1091
+
1092
+ def edible
1093
+ @attributes[:edible]
1094
+ end
1095
+ end
1096
+
1097
+ def tests_can_handle_polymorphism
1098
+ email_serializer = Class.new(ActiveModel::Serializer) do
1099
+ attributes :subject, :body
1100
+ end
1101
+
1102
+ email_class = Class.new(Model) do
1103
+ def self.to_s
1104
+ "Email"
1105
+ end
1106
+
1107
+ define_method :active_model_serializer do
1108
+ email_serializer
1109
+ end
1110
+ end
1111
+
1112
+ attachment_serializer = Class.new(ActiveModel::Serializer) do
1113
+ attributes :name, :url
1114
+ has_one :attachable, :polymorphic => true
1115
+ end
1116
+
1117
+ email = email_class.new :subject => 'foo', :body => 'bar'
1118
+
1119
+ attachment = Attachment.new :name => 'logo.png', :url => 'http://example.com/logo.png', :attachable => email
1120
+
1121
+ actual = attachment_serializer.new(attachment, {}).as_json
1122
+
1123
+ assert_equal({
1124
+ :name => 'logo.png',
1125
+ :url => 'http://example.com/logo.png',
1126
+ :attachable => {
1127
+ :type => :email,
1128
+ :email => { :subject => 'foo', :body => 'bar' }
1129
+ }
1130
+ }, actual)
1131
+ end
1132
+
1133
+ def test_can_handle_polymoprhic_ids
1134
+ email_serializer = Class.new(ActiveModel::Serializer) do
1135
+ attributes :subject, :body
1136
+ end
1137
+
1138
+ email_class = Class.new(Model) do
1139
+ def self.to_s
1140
+ "Email"
1141
+ end
1142
+
1143
+ define_method :active_model_serializer do
1144
+ email_serializer
1145
+ end
1146
+ end
1147
+
1148
+ attachment_serializer = Class.new(ActiveModel::Serializer) do
1149
+ embed :ids
1150
+ attributes :name, :url
1151
+ has_one :attachable, :polymorphic => true
1152
+ end
1153
+
1154
+ email = email_class.new :id => 1
1155
+
1156
+ attachment = Attachment.new :name => 'logo.png', :url => 'http://example.com/logo.png', :attachable => email
1157
+
1158
+ actual = attachment_serializer.new(attachment, {}).as_json
1159
+
1160
+ assert_equal({
1161
+ :name => 'logo.png',
1162
+ :url => 'http://example.com/logo.png',
1163
+ :attachable => {
1164
+ :type => :email,
1165
+ :id => 1
1166
+ }
1167
+ }, actual)
1168
+ end
1169
+
1170
+ def test_polymorphic_associations_are_included_at_root
1171
+ email_serializer = Class.new(ActiveModel::Serializer) do
1172
+ attributes :subject, :body, :id
1173
+ end
1174
+
1175
+ email_class = Class.new(Model) do
1176
+ def self.to_s
1177
+ "Email"
1178
+ end
1179
+
1180
+ define_method :active_model_serializer do
1181
+ email_serializer
1182
+ end
1183
+ end
1184
+
1185
+ attachment_serializer = Class.new(ActiveModel::Serializer) do
1186
+ root :attachment
1187
+ embed :ids, :include => true
1188
+ attributes :name, :url
1189
+ has_one :attachable, :polymorphic => true
1190
+ end
1191
+
1192
+ email = email_class.new :id => 1, :subject => "Hello", :body => "World"
1193
+
1194
+ attachment = Attachment.new :name => 'logo.png', :url => 'http://example.com/logo.png', :attachable => email
1195
+
1196
+ actual = attachment_serializer.new(attachment, {}).as_json
1197
+
1198
+ assert_equal({
1199
+ :attachment => {
1200
+ :name => 'logo.png',
1201
+ :url => 'http://example.com/logo.png',
1202
+ :attachable => {
1203
+ :type => :email,
1204
+ :id => 1
1205
+ }},
1206
+ :emails => [{
1207
+ :id => 1,
1208
+ :subject => "Hello",
1209
+ :body => "World"
1210
+ }]
1211
+ }, actual)
1212
+ end
1213
+
1214
+ def test_multiple_polymorphic_associations
1215
+ email_serializer = Class.new(ActiveModel::Serializer) do
1216
+ attributes :subject, :body, :id
1217
+ end
1218
+
1219
+ orange_serializer = Class.new(ActiveModel::Serializer) do
1220
+ embed :ids, :include => true
1221
+
1222
+ attributes :plu, :id
1223
+ has_one :readable, :polymorphic => true
1224
+ end
1225
+
1226
+ email_class = Class.new(Model) do
1227
+ def self.to_s
1228
+ "Email"
1229
+ end
1230
+
1231
+ define_method :active_model_serializer do
1232
+ email_serializer
1233
+ end
1234
+ end
1235
+
1236
+ orange_class = Class.new(Model) do
1237
+ def self.to_s
1238
+ "Orange"
1239
+ end
1240
+
1241
+ def readable
1242
+ @attributes[:readable]
1243
+ end
1244
+
1245
+ define_method :active_model_serializer do
1246
+ orange_serializer
1247
+ end
1248
+ end
1249
+
1250
+ attachment_serializer = Class.new(ActiveModel::Serializer) do
1251
+ root :attachment
1252
+ embed :ids, :include => true
1253
+
1254
+ attributes :name, :url
1255
+
1256
+ has_one :attachable, :polymorphic => true
1257
+ has_one :readable, :polymorphic => true
1258
+ has_one :edible, :polymorphic => true
1259
+ end
1260
+
1261
+ email = email_class.new :id => 1, :subject => "Hello", :body => "World"
1262
+ orange = orange_class.new :id => 1, :plu => "3027", :readable => email
1263
+
1264
+ attachment = Attachment.new({
1265
+ :name => 'logo.png',
1266
+ :url => 'http://example.com/logo.png',
1267
+ :attachable => email,
1268
+ :readable => email,
1269
+ :edible => orange
1270
+ })
1271
+
1272
+ actual = attachment_serializer.new(attachment, {}).as_json
1273
+
1274
+ assert_equal({
1275
+ :emails => [{
1276
+ :subject => "Hello",
1277
+ :body => "World",
1278
+ :id => 1
1279
+ }],
1280
+
1281
+ :oranges => [{
1282
+ :plu => "3027",
1283
+ :id => 1,
1284
+ :readable => { :type => :email, :id => 1 }
1285
+ }],
1286
+
1287
+ :attachment => {
1288
+ :name => 'logo.png',
1289
+ :url => 'http://example.com/logo.png',
1290
+ :attachable => { :type => :email, :id => 1 },
1291
+ :readable => { :type => :email, :id => 1 },
1292
+ :edible => { :type => :orange, :id => 1 }
1293
+ }
1294
+ }, actual)
1295
+ end
1296
+
1297
+ def test_raises_an_error_when_a_child_serializer_includes_associations_when_the_source_doesnt
1298
+ attachment_serializer = Class.new(ActiveModel::Serializer) do
1299
+ attributes :name
1300
+ end
1301
+
1302
+ fruit_serializer = Class.new(ActiveModel::Serializer) do
1303
+ embed :ids, :include => true
1304
+ has_one :attachment, :serializer => attachment_serializer
1305
+ attribute :color
1306
+ end
1307
+
1308
+ banana_class = Class.new Model do
1309
+ def self.to_s
1310
+ 'banana'
1311
+ end
1312
+
1313
+ def attachment
1314
+ @attributes[:attachment]
1315
+ end
1316
+
1317
+ define_method :active_model_serializer do
1318
+ fruit_serializer
1319
+ end
1320
+ end
1321
+
1322
+ strawberry_class = Class.new Model do
1323
+ def self.to_s
1324
+ 'strawberry'
1325
+ end
1326
+
1327
+ def attachment
1328
+ @attributes[:attachment]
1329
+ end
1330
+
1331
+ define_method :active_model_serializer do
1332
+ fruit_serializer
1333
+ end
1334
+ end
1335
+
1336
+ smoothie = Class.new do
1337
+ attr_reader :base, :flavor
1338
+
1339
+ def initialize(base, flavor)
1340
+ @base, @flavor = base, flavor
1341
+ end
1342
+ end
1343
+
1344
+ smoothie_serializer = Class.new(ActiveModel::Serializer) do
1345
+ root false
1346
+ embed :ids, :include => true
1347
+
1348
+ has_one :base, :polymorphic => true
1349
+ has_one :flavor, :polymorphic => true
1350
+ end
1351
+
1352
+ banana_attachment = Attachment.new({
1353
+ :name => 'banana_blending.md',
1354
+ :id => 3,
1355
+ })
1356
+
1357
+ strawberry_attachment = Attachment.new({
1358
+ :name => 'strawberry_cleaning.doc',
1359
+ :id => 4
1360
+ })
1361
+
1362
+ banana = banana_class.new :color => "yellow", :id => 1, :attachment => banana_attachment
1363
+ strawberry = strawberry_class.new :color => "red", :id => 2, :attachment => strawberry_attachment
1364
+
1365
+ smoothie = smoothie_serializer.new(smoothie.new(banana, strawberry))
1366
+
1367
+ assert_raise ActiveModel::Serializer::IncludeError do
1368
+ smoothie.as_json
1369
+ end
1370
+ end
1371
+
1372
+ def tests_includes_does_not_include_nil_polymoprhic_associations
1373
+ post_serializer = Class.new(ActiveModel::Serializer) do
1374
+ root :post
1375
+ embed :ids, :include => true
1376
+ has_one :author, :polymorphic => true
1377
+ attributes :title
1378
+ end
1379
+
1380
+ post = Post.new(:title => 'Foo')
1381
+
1382
+ actual = post_serializer.new(post).as_json
1383
+
1384
+ assert_equal({
1385
+ :post => {
1386
+ :title => 'Foo',
1387
+ :author => nil
1388
+ }
1389
+ }, actual)
1390
+ end
893
1391
  end