active_model_serializers 0.9.0 → 0.9.8

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.
Files changed (61) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +113 -0
  3. data/README.md +112 -19
  4. data/lib/action_controller/serialization.rb +35 -8
  5. data/lib/action_controller/serialization_test_case.rb +4 -4
  6. data/lib/active_model/array_serializer.rb +13 -10
  7. data/lib/active_model/default_serializer.rb +2 -6
  8. data/lib/active_model/serializable.rb +30 -11
  9. data/lib/active_model/serializable/utils.rb +16 -0
  10. data/lib/active_model/serializer.rb +90 -40
  11. data/lib/active_model/serializer/{associations.rb → association.rb} +8 -52
  12. data/lib/active_model/serializer/association/has_many.rb +39 -0
  13. data/lib/active_model/serializer/association/has_one.rb +25 -0
  14. data/lib/active_model/serializer/generators/serializer/scaffold_controller_generator.rb +1 -1
  15. data/lib/active_model/serializer/railtie.rb +12 -0
  16. data/lib/active_model/serializer/version.rb +1 -1
  17. data/lib/active_model_serializers.rb +1 -1
  18. data/lib/active_model_serializers/model/caching.rb +25 -0
  19. data/test/benchmark/app.rb +60 -0
  20. data/test/benchmark/benchmarking_support.rb +67 -0
  21. data/test/benchmark/bm_active_record.rb +41 -0
  22. data/test/benchmark/setup.rb +75 -0
  23. data/test/benchmark/tmp/miniprofiler/mp_timers_6eqewtfgrhitvq5gqm25 +0 -0
  24. data/test/benchmark/tmp/miniprofiler/mp_timers_8083sx03hu72pxz1a4d0 +0 -0
  25. data/test/benchmark/tmp/miniprofiler/mp_timers_fyz2gsml4z0ph9kpoy1c +0 -0
  26. data/test/benchmark/tmp/miniprofiler/mp_timers_hjry5rc32imd42oxoi48 +0 -0
  27. data/test/benchmark/tmp/miniprofiler/mp_timers_m8fpoz2cvt3g9agz0bs3 +0 -0
  28. data/test/benchmark/tmp/miniprofiler/mp_timers_p92m2drnj1i568u3sta0 +0 -0
  29. data/test/benchmark/tmp/miniprofiler/mp_timers_qg52tpca3uesdfguee9i +0 -0
  30. data/test/benchmark/tmp/miniprofiler/mp_timers_s15t1a6mvxe0z7vjv790 +0 -0
  31. data/test/benchmark/tmp/miniprofiler/mp_timers_x8kal3d17nfds6vp4kcj +0 -0
  32. data/test/benchmark/tmp/miniprofiler/mp_views_127.0.0.1 +0 -0
  33. data/test/fixtures/active_record.rb +4 -0
  34. data/test/fixtures/poro.rb +149 -1
  35. data/test/fixtures/template.html.erb +1 -0
  36. data/test/integration/action_controller/namespaced_serialization_test.rb +105 -0
  37. data/test/integration/action_controller/serialization_test.rb +5 -5
  38. data/test/integration/action_controller/serialization_test_case_test.rb +10 -0
  39. data/test/integration/active_record/active_record_test.rb +19 -2
  40. data/test/test_app.rb +3 -0
  41. data/test/tmp/app/assets/javascripts/accounts.js +2 -0
  42. data/test/tmp/app/assets/stylesheets/accounts.css +4 -0
  43. data/test/tmp/app/controllers/accounts_controller.rb +2 -0
  44. data/test/tmp/app/helpers/accounts_helper.rb +2 -0
  45. data/test/tmp/app/serializers/account_serializer.rb +3 -0
  46. data/test/tmp/config/routes.rb +1 -0
  47. data/test/unit/active_model/array_serializer/options_test.rb +16 -0
  48. data/test/unit/active_model/array_serializer/serialization_test.rb +18 -1
  49. data/test/unit/active_model/serializer/associations/build_serializer_test.rb +15 -0
  50. data/test/unit/active_model/serializer/associations_test.rb +30 -0
  51. data/test/unit/active_model/serializer/attributes_test.rb +16 -0
  52. data/test/unit/active_model/serializer/config_test.rb +3 -0
  53. data/test/unit/active_model/serializer/has_many_polymorphic_test.rb +189 -0
  54. data/test/unit/active_model/serializer/has_many_test.rb +52 -17
  55. data/test/unit/active_model/serializer/has_one_and_has_many_test.rb +27 -0
  56. data/test/unit/active_model/serializer/has_one_polymorphic_test.rb +196 -0
  57. data/test/unit/active_model/serializer/has_one_test.rb +46 -0
  58. data/test/unit/active_model/serializer/options_test.rb +27 -0
  59. data/test/unit/active_model/serializer/url_helpers_test.rb +35 -0
  60. data/test/unit/active_model/serilizable_test.rb +50 -0
  61. metadata +98 -25
@@ -111,17 +111,34 @@ module ActiveModel
111
111
 
112
112
  assert_equal({
113
113
  'post' => { title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id } },
114
- comments: [{ content: 'C1' }, { content: 'C2' }]
114
+ 'comments' => [{ content: 'C1' }, { content: 'C2' }]
115
115
  }, @post_serializer.as_json)
116
116
  end
117
117
 
118
+ def test_associations_embedding_ids_including_objects_serialization_when_invoked_from_parent_serializer
119
+ @association.embed = :ids
120
+ @association.embed_in_root = true
121
+
122
+ category = Category.new(name: 'Name 1')
123
+ category.instance_variable_set(:@posts, [@post])
124
+ category_serializer = CategorySerializer.new(category)
125
+
126
+ assert_equal({
127
+ 'category' => {
128
+ name: 'Name 1',
129
+ posts: [{ title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id } }]
130
+ },
131
+ "comments" => [{ content: 'C1' }, { content: 'C2' }]
132
+ }, category_serializer.as_json)
133
+ end
134
+
118
135
  def test_associations_embedding_nothing_including_objects_serialization_using_as_json
119
136
  @association.embed = nil
120
137
  @association.embed_in_root = true
121
138
 
122
139
  assert_equal({
123
140
  'post' => { title: 'Title 1', body: 'Body 1' },
124
- comments: [{ content: 'C1' }, { content: 'C2' }]
141
+ 'comments' => [{ content: 'C1' }, { content: 'C2' }]
125
142
  }, @post_serializer.as_json)
126
143
  end
127
144
 
@@ -138,7 +155,7 @@ module ActiveModel
138
155
 
139
156
  assert_equal({
140
157
  'post' => { title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id } },
141
- comments: [{ content: 'C1!' }, { content: 'C2!' }]
158
+ 'comments' => [{ content: 'C1!' }, { content: 'C2!' }]
142
159
  }, @post_serializer.as_json)
143
160
  end
144
161
 
@@ -153,13 +170,13 @@ module ActiveModel
153
170
 
154
171
  assert_equal({
155
172
  'post' => { title: 'Title 1', body: 'Body 1', 'comment_ids' => @post.comments.map { |c| c.object_id } },
156
- comments: { my_content: ['fake'] }
173
+ 'comments' => { my_content: ['fake'] }
157
174
  }, @post_serializer.as_json)
158
175
  end
159
176
 
160
177
  def test_associations_embedding_objects_using_a_given_array_serializer
161
178
  @association.serializer_from_options = Class.new(ArraySerializer) do
162
- def serializable_object
179
+ def serializable_object(options={})
163
180
  { my_content: ['fake'] }
164
181
  end
165
182
  end
@@ -174,16 +191,16 @@ module ActiveModel
174
191
  @association.embed_in_root_key = :linked
175
192
  @association.embed = :ids
176
193
  assert_equal({
194
+ 'post' => {
195
+ title: 'Title 1', body: 'Body 1',
196
+ 'comment_ids' => @post.comments.map(&:object_id)
197
+ },
177
198
  linked: {
178
- comments: [
199
+ 'comments' => [
179
200
  { content: 'C1' },
180
201
  { content: 'C2' }
181
202
  ]
182
203
  },
183
- 'post' => {
184
- title: 'Title 1', body: 'Body 1',
185
- 'comment_ids' => @post.comments.map(&:object_id)
186
- }
187
204
  }, @post_serializer.as_json)
188
205
  end
189
206
 
@@ -194,18 +211,18 @@ module ActiveModel
194
211
  @association.embed_namespace = :links
195
212
  @association.key = :comments
196
213
  assert_equal({
197
- linked: {
198
- comments: [
199
- { content: 'C1' },
200
- { content: 'C2' }
201
- ]
202
- },
203
214
  'post' => {
204
215
  title: 'Title 1', body: 'Body 1',
205
216
  links: {
206
217
  comments: @post.comments.map(&:object_id)
207
218
  }
208
- }
219
+ },
220
+ linked: {
221
+ 'comments' => [
222
+ { content: 'C1' },
223
+ { content: 'C2' }
224
+ ]
225
+ },
209
226
  }, @post_serializer.as_json)
210
227
  end
211
228
 
@@ -225,6 +242,24 @@ module ActiveModel
225
242
  }
226
243
  }, @post_serializer.as_json)
227
244
  end
245
+
246
+ def test_associations_name_key_embedding_ids_serialization_using_serializable_hash
247
+ @association = NameKeyPostSerializer._associations[:comments]
248
+ @association.embed = :ids
249
+
250
+ assert_equal({
251
+ title: 'Title 1', body: 'Body 1', 'comments' => @post.comments.map { |c| c.object_id }
252
+ }, NameKeyPostSerializer.new(@post).serializable_hash)
253
+ end
254
+
255
+ def test_associations_name_key_embedding_ids_serialization_using_as_json
256
+ @association = NameKeyPostSerializer._associations[:comments]
257
+ @association.embed = :ids
258
+
259
+ assert_equal({
260
+ 'name_key_post' => { title: 'Title 1', body: 'Body 1', 'comments' => @post.comments.map { |c| c.object_id } }
261
+ }, NameKeyPostSerializer.new(@post).as_json)
262
+ end
228
263
  end
229
264
  end
230
265
  end
@@ -0,0 +1,27 @@
1
+ require 'test_helper'
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ class HasOneAndHasManyTest < Minitest::Test
6
+ def setup
7
+ @post = SpecialPost.new({ title: 'T1', body: 'B1'})
8
+ @post_serializer = SpecialPostSerializer.new(@post)
9
+ end
10
+
11
+ def teardown
12
+ end
13
+
14
+ def test_side_load_has_one_and_has_many_in_same_array
15
+ assert_equal({
16
+ "post" => {
17
+ title: 'T1',
18
+ body: 'B1',
19
+ 'comment_ids' => @post.comments.map { |c| c.object_id },
20
+ 'special_comment_id' => @post_serializer.special_comment.object_id,
21
+ },
22
+ "comments" => [{ content: 'C1' }, { content: 'C2' }, { content: 'special' }]
23
+ }, @post_serializer.as_json(root: 'post'))
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,196 @@
1
+ require 'test_helper'
2
+
3
+ module ActiveModel
4
+ class Serializer
5
+ class HasOnePolymorphicTest < ActiveModel::TestCase
6
+ def setup
7
+ @association = InterviewSerializer._associations[:attachment]
8
+ @old_association = @association.dup
9
+
10
+ @interview = Interview.new({ text: 'Text 1' })
11
+ @interview_serializer = InterviewSerializer.new(@interview)
12
+ end
13
+
14
+ def teardown
15
+ InterviewSerializer._associations[:attachment] = @old_association
16
+ end
17
+
18
+ def model_name(object)
19
+ object.class.to_s.demodulize.underscore.to_sym
20
+ end
21
+
22
+ def test_associations_definition
23
+ assert_equal 1, InterviewSerializer._associations.length
24
+ assert_kind_of Association::HasOne, @association
25
+ assert_equal true, @association.polymorphic
26
+ assert_equal 'attachment', @association.name
27
+ end
28
+
29
+ def test_associations_embedding_ids_serialization_using_serializable_hash
30
+ @association.embed = :ids
31
+
32
+ assert_equal({
33
+ text: 'Text 1',
34
+ 'attachment_id' => {
35
+ type: model_name(@interview.attachment),
36
+ id: @interview.attachment.object_id
37
+ }
38
+ }, @interview_serializer.serializable_hash)
39
+ end
40
+
41
+ def test_associations_embedding_ids_serialization_using_as_json
42
+ @association.embed = :ids
43
+
44
+ assert_equal({
45
+ 'interview' => {
46
+ text: 'Text 1',
47
+ 'attachment_id' => {
48
+ type: model_name(@interview.attachment),
49
+ id: @interview.attachment.object_id
50
+ }
51
+ }
52
+ }, @interview_serializer.as_json)
53
+ end
54
+
55
+ def test_associations_embedding_ids_serialization_using_serializable_hash_and_key_from_options
56
+ @association.embed = :ids
57
+ @association.key = 'key'
58
+
59
+ assert_equal({
60
+ text: 'Text 1',
61
+ 'key' => {
62
+ type: model_name(@interview.attachment),
63
+ id: @interview.attachment.object_id
64
+ }
65
+ }, @interview_serializer.serializable_hash)
66
+ end
67
+
68
+ def test_associations_embedding_objects_serialization_using_serializable_hash
69
+ @association.embed = :objects
70
+
71
+ assert_equal({
72
+ text: 'Text 1',
73
+ attachment: {
74
+ type: model_name(@interview.attachment),
75
+ model_name(@interview.attachment) => { url: 'U1'}
76
+ }
77
+ }, @interview_serializer.serializable_hash)
78
+ end
79
+
80
+ def test_associations_embedding_objects_serialization_using_as_json
81
+ @association.embed = :objects
82
+
83
+ assert_equal({
84
+ 'interview' => {
85
+ text: 'Text 1',
86
+ attachment: {
87
+ type: model_name(@interview.attachment),
88
+ model_name(@interview.attachment) => { url: 'U1'}
89
+ }
90
+ }
91
+ }, @interview_serializer.as_json)
92
+ end
93
+
94
+ def test_associations_embedding_nil_ids_serialization_using_as_json
95
+ @association.embed = :ids
96
+ @interview.instance_eval do
97
+ def attachment
98
+ nil
99
+ end
100
+ end
101
+
102
+ assert_equal({
103
+ 'interview' => { text: 'Text 1', 'attachment_id' => nil }
104
+ }, @interview_serializer.as_json)
105
+ end
106
+
107
+ def test_associations_embedding_nil_objects_serialization_using_as_json
108
+ @association.embed = :objects
109
+ @interview.instance_eval do
110
+ def attachment
111
+ nil
112
+ end
113
+ end
114
+
115
+ assert_equal({
116
+ 'interview' => { text: 'Text 1', attachment: nil }
117
+ }, @interview_serializer.as_json)
118
+ end
119
+
120
+ def test_associations_embedding_objects_serialization_using_serializable_hash_and_root_from_options
121
+ @association.embed = :objects
122
+ @association.embedded_key = 'root'
123
+
124
+ assert_equal({
125
+ text: 'Text 1',
126
+ 'root' => {
127
+ type: model_name(@interview.attachment),
128
+ model_name(@interview.attachment) => { url: 'U1'}
129
+ }
130
+ }, @interview_serializer.serializable_hash)
131
+ end
132
+
133
+ def test_associations_embedding_ids_including_objects_serialization_using_serializable_hash
134
+ @association.embed = :ids
135
+ @association.embed_in_root = true
136
+
137
+ assert_equal({
138
+ text: 'Text 1',
139
+ 'attachment_id' => {
140
+ type: model_name(@interview.attachment),
141
+ id: @interview.attachment.object_id
142
+ }
143
+ }, @interview_serializer.serializable_hash)
144
+ end
145
+
146
+ def test_associations_embedding_ids_including_objects_serialization_using_as_json
147
+ @association.embed = :ids
148
+ @association.embed_in_root = true
149
+
150
+ assert_equal({
151
+ 'interview' => {
152
+ text: 'Text 1',
153
+ 'attachment_id' => {
154
+ type: model_name(@interview.attachment),
155
+ id: @interview.attachment.object_id
156
+ }
157
+ },
158
+ "attachments" => [{
159
+ type: model_name(@interview.attachment),
160
+ model_name(@interview.attachment) => {
161
+ url: 'U1'
162
+ }
163
+ }]
164
+ }, @interview_serializer.as_json)
165
+ end
166
+
167
+ def test_associations_using_a_given_serializer
168
+ @association.embed = :ids
169
+ @association.embed_in_root = true
170
+ @association.serializer_from_options = Class.new(ActiveModel::Serializer) do
171
+ def name
172
+ 'fake'
173
+ end
174
+
175
+ attributes :name
176
+ end
177
+
178
+ assert_equal({
179
+ 'interview' => {
180
+ text: 'Text 1',
181
+ 'attachment_id' => {
182
+ type: model_name(@interview.attachment),
183
+ id: @interview.attachment.object_id
184
+ }
185
+ },
186
+ "attachments" => [{
187
+ type: model_name(@interview.attachment),
188
+ model_name(@interview.attachment) => {
189
+ name: 'fake'
190
+ }
191
+ }]
192
+ }, @interview_serializer.as_json)
193
+ end
194
+ end
195
+ end
196
+ end
@@ -131,6 +131,20 @@ module ActiveModel
131
131
  }, @user_serializer.as_json)
132
132
  end
133
133
 
134
+ def test_associations_embedding_ids_including_objects_serialization_when_invoked_from_parent_serializer
135
+ @association.embed = :ids
136
+ @association.embed_in_root = true
137
+
138
+ user_info = UserInfo.new
139
+ user_info.instance_variable_set(:@user, @user)
140
+ user_info_serializer = UserInfoSerializer.new(user_info)
141
+
142
+ assert_equal({
143
+ 'user_info' => { user: { name: 'Name 1', email: 'mail@server.com', 'profile_id' => @user.profile.object_id } },
144
+ 'profiles' => [{ name: 'N1', description: 'D1' }]
145
+ }, user_info_serializer.as_json)
146
+ end
147
+
134
148
  def test_associations_embedding_ids_using_a_given_serializer
135
149
  @association.embed = :ids
136
150
  @association.embed_in_root = true
@@ -162,6 +176,20 @@ module ActiveModel
162
176
  }, @user_serializer.as_json)
163
177
  end
164
178
 
179
+ def test_associations_embedding_objects_with_nil_values
180
+ user_info = UserInfo.new
181
+ user_info.instance_eval do
182
+ def user
183
+ nil
184
+ end
185
+ end
186
+ user_info_serializer = UserInfoSerializer.new(user_info)
187
+
188
+ assert_equal({
189
+ 'user_info' => { user: nil }
190
+ }, user_info_serializer.as_json)
191
+ end
192
+
165
193
  def test_associations_embedding_ids_using_embed_namespace
166
194
  @association.embed_namespace = :links
167
195
  @association.embed = :ids
@@ -202,6 +230,24 @@ module ActiveModel
202
230
  }
203
231
  }, @user_serializer.as_json)
204
232
  end
233
+
234
+ def test_associations_name_key_embedding_ids_serialization_using_serializable_hash
235
+ @association = NameKeyUserSerializer._associations[:profile]
236
+ @association.embed = :ids
237
+
238
+ assert_equal({
239
+ name: 'Name 1', email: 'mail@server.com', 'profile' => @user.profile.object_id
240
+ }, NameKeyUserSerializer.new(@user).serializable_hash)
241
+ end
242
+
243
+ def test_associations_name_key_embedding_ids_serialization_using_as_json
244
+ @association = NameKeyUserSerializer._associations[:profile]
245
+ @association.embed = :ids
246
+
247
+ assert_equal({
248
+ 'name_key_user' => { name: 'Name 1', email: 'mail@server.com', 'profile' => @user.profile.object_id }
249
+ }, NameKeyUserSerializer.new(@user).as_json)
250
+ end
205
251
  end
206
252
  end
207
253
  end
@@ -11,5 +11,32 @@ module ActiveModel
11
11
  assert_equal({foo: :bar}, @serializer.context)
12
12
  end
13
13
  end
14
+
15
+ class SerializationOptionsTest < Minitest::Test
16
+ def setup
17
+ @profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
18
+ @profile_serializer = ProfileSerializer.new(@profile)
19
+ @profile_serializer.instance_eval do
20
+ def description
21
+ serialization_options[:force_the_description]
22
+ end
23
+ end
24
+
25
+ @category = Category.new({name: 'Category 1'})
26
+ @category_serializer = CategorySerializer.new(@category)
27
+ end
28
+
29
+ def test_filtered_attributes_serialization
30
+ forced_description = "This is a test"
31
+ assert_equal({
32
+ 'profile' => { name: 'Name 1', description: forced_description }
33
+ }, @profile_serializer.as_json(force_the_description: forced_description))
34
+ end
35
+
36
+ def test_filtered_attributes_serialization_across_association
37
+ assert_equal("'T1'",
38
+ @category_serializer.as_json(highlight_keyword: 'T1')['category'][:posts][0][:title])
39
+ end
40
+ end
14
41
  end
15
42
  end