active_model_serializers 0.10.0.rc1 → 0.10.0.rc2

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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -2
  3. data/Gemfile +1 -1
  4. data/README.md +6 -3
  5. data/lib/action_controller/serialization.rb +9 -1
  6. data/lib/active_model/serializer.rb +15 -21
  7. data/lib/active_model/serializer/adapter.rb +13 -4
  8. data/lib/active_model/serializer/adapter/flatten_json.rb +12 -0
  9. data/lib/active_model/serializer/adapter/fragment_cache.rb +5 -5
  10. data/lib/active_model/serializer/adapter/json.rb +8 -10
  11. data/lib/active_model/serializer/adapter/json_api.rb +34 -30
  12. data/lib/active_model/serializer/adapter/json_api/fragment_cache.rb +3 -2
  13. data/lib/active_model/serializer/array_serializer.rb +8 -5
  14. data/lib/active_model/serializer/configuration.rb +1 -1
  15. data/lib/active_model/serializer/fieldset.rb +2 -2
  16. data/lib/active_model/serializer/railtie.rb +8 -0
  17. data/lib/active_model/serializer/version.rb +1 -1
  18. data/lib/active_model_serializers.rb +1 -0
  19. data/lib/generators/serializer/resource_override.rb +12 -0
  20. data/test/action_controller/adapter_selector_test.rb +7 -5
  21. data/test/action_controller/explicit_serializer_test.rb +33 -9
  22. data/test/action_controller/json_api_linked_test.rb +25 -19
  23. data/test/action_controller/rescue_from_test.rb +32 -0
  24. data/test/action_controller/serialization_scope_name_test.rb +2 -2
  25. data/test/action_controller/serialization_test.rb +41 -23
  26. data/test/adapter/fragment_cache_test.rb +1 -1
  27. data/test/adapter/json/belongs_to_test.rb +9 -2
  28. data/test/adapter/json/collection_test.rb +16 -2
  29. data/test/adapter/json/has_many_test.rb +1 -1
  30. data/test/adapter/json_api/belongs_to_test.rb +45 -35
  31. data/test/adapter/json_api/collection_test.rb +30 -23
  32. data/test/adapter/json_api/has_many_embed_ids_test.rb +2 -2
  33. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +14 -14
  34. data/test/adapter/json_api/has_many_test.rb +22 -18
  35. data/test/adapter/json_api/has_one_test.rb +8 -6
  36. data/test/adapter/json_api/linked_test.rb +97 -71
  37. data/test/adapter/json_test.rb +1 -1
  38. data/test/adapter_test.rb +1 -1
  39. data/test/array_serializer_test.rb +14 -0
  40. data/test/fixtures/poro.rb +31 -7
  41. data/test/generators/scaffold_controller_generator_test.rb +24 -0
  42. data/test/{serializers/generators_test.rb → generators/serializer_generator_test.rb} +2 -10
  43. data/test/serializers/adapter_for_test.rb +1 -1
  44. data/test/serializers/associations_test.rb +21 -0
  45. data/test/serializers/attribute_test.rb +16 -1
  46. data/test/serializers/attributes_test.rb +35 -0
  47. data/test/serializers/cache_test.rb +14 -4
  48. data/test/serializers/configuration_test.rb +1 -1
  49. data/test/serializers/meta_test.rb +38 -9
  50. data/test/serializers/serializer_for_test.rb +9 -0
  51. data/test/test_helper.rb +10 -7
  52. metadata +12 -5
@@ -10,9 +10,10 @@ module ActiveModel
10
10
  core_non_cached = non_cached_hash.first
11
11
  no_root_cache = cached_hash.delete_if {|key, value| key == core_cached[0] }
12
12
  no_root_non_cache = non_cached_hash.delete_if {|key, value| key == core_non_cached[0] }
13
- cached_resource = (core_cached[1]) ? core_cached[1].merge(core_non_cached[1]) : core_non_cached[1]
13
+ cached_resource = (core_cached[1]) ? core_cached[1].deep_merge(core_non_cached[1]) : core_non_cached[1]
14
14
  hash = (root) ? { root => cached_resource } : cached_resource
15
- hash.merge no_root_non_cache.merge no_root_cache
15
+
16
+ hash.deep_merge no_root_non_cache.deep_merge no_root_cache
16
17
  end
17
18
 
18
19
  end
@@ -7,21 +7,24 @@ module ActiveModel
7
7
  attr_reader :meta, :meta_key
8
8
 
9
9
  def initialize(objects, options = {})
10
- options.merge!(root: nil)
11
-
12
- @objects = objects.map do |object|
10
+ @resource = objects
11
+ @objects = objects.map do |object|
13
12
  serializer_class = options.fetch(
14
13
  :serializer,
15
14
  ActiveModel::Serializer.serializer_for(object)
16
15
  )
17
- serializer_class.new(object, options)
16
+ serializer_class.new(object, options.except(:serializer))
18
17
  end
19
18
  @meta = options[:meta]
20
19
  @meta_key = options[:meta_key]
21
20
  end
22
21
 
23
22
  def json_key
24
- @objects.first.json_key if @objects.first
23
+ if @objects.first
24
+ @objects.first.json_key.pluralize
25
+ else
26
+ @resource.name.downcase.pluralize if @resource.try(:name)
27
+ end
25
28
  end
26
29
 
27
30
  def root=(root)
@@ -6,7 +6,7 @@ module ActiveModel
6
6
 
7
7
  included do |base|
8
8
  base.config.array_serializer = ActiveModel::Serializer::ArraySerializer
9
- base.config.adapter = :json
9
+ base.config.adapter = :flatten_json
10
10
  end
11
11
  end
12
12
  end
@@ -12,8 +12,8 @@ module ActiveModel
12
12
  end
13
13
 
14
14
  def fields_for(serializer)
15
- key = serializer.json_key || serializer.class.root_name
16
- fields[key.to_sym]
15
+ key = serializer.json_key
16
+ fields[key.to_sym] || fields[key.pluralize.to_sym]
17
17
  end
18
18
 
19
19
  private
@@ -0,0 +1,8 @@
1
+ module ActiveModel
2
+ class Railtie < Rails::Railtie
3
+ initializer 'generators' do |app|
4
+ app.load_generators
5
+ require 'generators/serializer/resource_override'
6
+ end
7
+ end
8
+ end
@@ -1,5 +1,5 @@
1
1
  module ActiveModel
2
2
  class Serializer
3
- VERSION = "0.10.0.rc1"
3
+ VERSION = "0.10.0.rc2"
4
4
  end
5
5
  end
@@ -2,6 +2,7 @@ require 'active_model'
2
2
  require 'active_model/serializer/version'
3
3
  require 'active_model/serializer'
4
4
  require 'active_model/serializer/fieldset'
5
+ require 'active_model/serializer/railtie'
5
6
 
6
7
  begin
7
8
  require 'action_controller'
@@ -0,0 +1,12 @@
1
+ require 'rails/generators'
2
+ require 'rails/generators/rails/resource/resource_generator'
3
+
4
+ module Rails
5
+ module Generators
6
+ class ResourceGenerator
7
+ def add_serializer
8
+ invoke 'serializer'
9
+ end
10
+ end
11
+ end
12
+ end
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
  module ActionController
4
4
  module Serialization
5
5
  class AdapterSelectorTest < ActionController::TestCase
6
- class MyController < ActionController::Base
6
+ class AdapterSelectorTestController < ActionController::Base
7
7
  def render_using_default_adapter
8
8
  @profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
9
9
  render json: @profile
@@ -20,7 +20,7 @@ module ActionController
20
20
  end
21
21
  end
22
22
 
23
- tests MyController
23
+ tests AdapterSelectorTestController
24
24
 
25
25
  def test_render_using_default_adapter
26
26
  get :render_using_default_adapter
@@ -32,10 +32,12 @@ module ActionController
32
32
 
33
33
  expected = {
34
34
  data: {
35
- name: "Name 1",
36
- description: "Description 1",
37
35
  id: assigns(:profile).id.to_s,
38
- type: "profiles"
36
+ type: "profiles",
37
+ attributes: {
38
+ name: "Name 1",
39
+ description: "Description 1",
40
+ }
39
41
  }
40
42
  }
41
43
 
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
  module ActionController
4
4
  module Serialization
5
5
  class ExplicitSerializerTest < ActionController::TestCase
6
- class MyController < ActionController::Base
6
+ class ExplicitSerializerTestController < ActionController::Base
7
7
  def render_using_explicit_serializer
8
8
  @profile = Profile.new(name: 'Name 1',
9
9
  description: 'Description 1',
@@ -55,9 +55,16 @@ module ActionController
55
55
 
56
56
  render json: [@post], each_serializer: PostPreviewSerializer
57
57
  end
58
+
59
+ def render_using_explicit_each_serializer
60
+ location = Location.new(id: 42, lat: '-23.550520', lng: '-46.633309')
61
+ place = Place.new(id: 1337, name: 'Amazing Place', locations: [location])
62
+
63
+ render json: place, each_serializer: PlaceSerializer
64
+ end
58
65
  end
59
66
 
60
- tests MyController
67
+ tests ExplicitSerializerTestController
61
68
 
62
69
  def test_render_using_explicit_serializer
63
70
  get :render_using_explicit_serializer
@@ -70,17 +77,15 @@ module ActionController
70
77
  get :render_array_using_explicit_serializer
71
78
  assert_equal 'application/json', @response.content_type
72
79
 
73
- expected = {
74
- 'paginated' => [
75
- { 'name' => 'Name 1' },
76
- { 'name' => 'Name 2' }
77
- ]
78
- }
80
+ expected = [
81
+ { 'name' => 'Name 1' },
82
+ { 'name' => 'Name 2' }
83
+ ]
79
84
 
80
85
  assert_equal expected.to_json, @response.body
81
86
  end
82
87
 
83
- def test_render_array_using_explicit_serializer
88
+ def test_render_array_using_implicit_serializer
84
89
  get :render_array_using_implicit_serializer
85
90
  assert_equal 'application/json', @response.content_type
86
91
 
@@ -105,6 +110,25 @@ module ActionController
105
110
 
106
111
  assert_equal expected.to_json, @response.body
107
112
  end
113
+
114
+ def test_render_using_explicit_each_serializer
115
+ get :render_using_explicit_each_serializer
116
+
117
+ expected = {
118
+ id: 1337,
119
+ name: "Amazing Place",
120
+ locations: [
121
+ {
122
+ id: 42,
123
+ lat: "-23.550520",
124
+ lng: "-46.633309",
125
+ place: "Nowhere" # is a virtual attribute on LocationSerializer
126
+ }
127
+ ]
128
+ }
129
+
130
+ assert_equal expected.to_json, response.body
131
+ end
108
132
  end
109
133
  end
110
134
  end
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
  module ActionController
4
4
  module Serialization
5
5
  class JsonApiLinkedTest < ActionController::TestCase
6
- class MyController < ActionController::Base
6
+ class JsonApiLinkedTestController < ActionController::Base
7
7
  def setup_post
8
8
  ActionController::Base.cache_store.clear
9
9
  @role1 = Role.new(id: 1, name: 'admin')
@@ -78,7 +78,7 @@ module ActionController
78
78
  end
79
79
  end
80
80
 
81
- tests MyController
81
+ tests JsonApiLinkedTestController
82
82
 
83
83
  def test_render_resource_without_include
84
84
  get :render_resource_without_include
@@ -91,7 +91,7 @@ module ActionController
91
91
  response = JSON.parse(@response.body)
92
92
  assert response.key? 'included'
93
93
  assert_equal 1, response['included'].size
94
- assert_equal 'Steve K.', response['included'].first['name']
94
+ assert_equal 'Steve K.', response['included'].first['attributes']['name']
95
95
  end
96
96
 
97
97
  def test_render_resource_with_nested_has_many_include
@@ -101,29 +101,35 @@ module ActionController
101
101
  {
102
102
  "id" => "1",
103
103
  "type" => "authors",
104
- "name" => "Steve K.",
105
- "links" => {
106
- "posts" => { "linkage" => [] },
107
- "roles" => { "linkage" => [{ "type" =>"roles", "id" => "1" }, { "type" =>"roles", "id" => "2" }] },
108
- "bio" => { "linkage" => nil }
104
+ "attributes" => {
105
+ "name" => "Steve K."
106
+ },
107
+ "relationships" => {
108
+ "posts" => { "data" => [] },
109
+ "roles" => { "data" => [{ "type" =>"roles", "id" => "1" }, { "type" =>"roles", "id" => "2" }] },
110
+ "bio" => { "data" => nil }
109
111
  }
110
112
  }, {
111
113
  "id" => "1",
112
114
  "type" => "roles",
113
- "name" => "admin",
114
- "description" => nil,
115
- "slug" => "admin-1",
116
- "links" => {
117
- "author" => { "linkage" => { "type" =>"authors", "id" => "1" } }
115
+ "attributes" => {
116
+ "name" => "admin",
117
+ "description" => nil,
118
+ "slug" => "admin-1"
119
+ },
120
+ "relationships" => {
121
+ "author" => { "data" => { "type" =>"authors", "id" => "1" } }
118
122
  }
119
123
  }, {
120
124
  "id" => "2",
121
125
  "type" => "roles",
122
- "name" => "colab",
123
- "description" => nil,
124
- "slug" => "colab-2",
125
- "links" => {
126
- "author" => { "linkage" => { "type" =>"authors", "id" => "1" } }
126
+ "attributes" => {
127
+ "name" => "colab",
128
+ "description" => nil,
129
+ "slug" => "colab-2"
130
+ },
131
+ "relationships" => {
132
+ "author" => { "data" => { "type" =>"authors", "id" => "1" } }
127
133
  }
128
134
  }
129
135
  ]
@@ -135,7 +141,7 @@ module ActionController
135
141
  response = JSON.parse(@response.body)
136
142
  assert response.key? 'included'
137
143
  assert_equal 1, response['included'].size
138
- assert_equal 'Anonymous', response['included'].first['name']
144
+ assert_equal 'Anonymous', response['included'].first['attributes']['name']
139
145
  end
140
146
 
141
147
  def test_render_collection_without_include
@@ -0,0 +1,32 @@
1
+ require 'test_helper'
2
+
3
+ module ActionController
4
+ module Serialization
5
+ class RescueFromTest < ActionController::TestCase
6
+ class RescueFromTestController < ActionController::Base
7
+ rescue_from Exception, with: :handle_error
8
+
9
+ def render_using_raise_error_serializer
10
+ @profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
11
+ render json: [@profile], serializer: RaiseErrorSerializer
12
+ end
13
+
14
+ def handle_error(exception)
15
+ render json: { errors: ['Internal Server Error'] }, status: :internal_server_error
16
+ end
17
+ end
18
+
19
+ tests RescueFromTestController
20
+
21
+ def test_rescue_from
22
+ get :render_using_raise_error_serializer
23
+
24
+ expected = {
25
+ errors: ['Internal Server Error']
26
+ }.to_json
27
+
28
+ assert_equal expected, @response.body
29
+ end
30
+ end
31
+ end
32
+ end
@@ -27,7 +27,7 @@ class DefaultScopeNameTest < ActionController::TestCase
27
27
 
28
28
  def test_default_scope_name
29
29
  get :render_new_user
30
- assert_equal '{"data":{"admin?":false,"id":"1","type":"users"}}', @response.body
30
+ assert_equal '{"data":{"id":"1","type":"users","attributes":{"admin?":false}}}', @response.body
31
31
  end
32
32
  end
33
33
 
@@ -58,6 +58,6 @@ class SerializationScopeNameTest < ActionController::TestCase
58
58
 
59
59
  def test_override_scope_name_with_controller
60
60
  get :render_new_user
61
- assert_equal '{"data":{"admin?":true,"id":"1","type":"users"}}', @response.body
61
+ assert_equal '{"data":{"id":"1","type":"users","attributes":{"admin?":true}}}', @response.body
62
62
  end
63
63
  end
@@ -3,15 +3,24 @@ require 'test_helper'
3
3
  module ActionController
4
4
  module Serialization
5
5
  class ImplicitSerializerTest < ActionController::TestCase
6
- class MyController < ActionController::Base
6
+ class ImplicitSerializationTestController < ActionController::Base
7
7
  def render_using_implicit_serializer
8
8
  @profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
9
9
  render json: @profile
10
10
  end
11
11
 
12
12
  def render_using_custom_root
13
- @profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
14
- render json: @profile, root: "custom_root"
13
+ with_adapter ActiveModel::Serializer::Adapter::Json do
14
+ @profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
15
+ render json: @profile, root: "custom_root"
16
+ end
17
+ end
18
+
19
+ def render_using_custom_root_and_meta
20
+ with_adapter ActiveModel::Serializer::Adapter::Json do
21
+ @profile = Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' })
22
+ render json: @profile, root: "custom_root", meta: { total: 10 }
23
+ end
15
24
  end
16
25
 
17
26
  def render_using_default_adapter_root
@@ -28,6 +37,16 @@ module ActionController
28
37
  render json: @profile, root: "profile", adapter: :json_api
29
38
  end
30
39
 
40
+ def render_array_using_custom_root_and_meta
41
+ with_adapter ActiveModel::Serializer::Adapter::Json do
42
+ array = [
43
+ Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' }),
44
+ Profile.new({ name: 'Name 2', description: 'Description 2', comments: 'Comments 2' })
45
+ ]
46
+ render json: array, root: "custom_root", meta: { total: 10 }
47
+ end
48
+ end
49
+
31
50
  def render_array_using_implicit_serializer
32
51
  array = [
33
52
  Profile.new({ name: 'Name 1', description: 'Description 1', comments: 'Comments 1' }),
@@ -139,7 +158,7 @@ module ActionController
139
158
  end
140
159
  end
141
160
 
142
- tests MyController
161
+ tests ImplicitSerializationTestController
143
162
 
144
163
  # We just have Null for now, this will change
145
164
  def test_render_using_implicit_serializer
@@ -154,22 +173,17 @@ module ActionController
154
173
  assert_equal expected.to_json, @response.body
155
174
  end
156
175
 
157
- def test_render_using_custom_root
158
- get :render_using_custom_root
159
-
160
- assert_equal 'application/json', @response.content_type
161
- assert_equal '{"custom_root":{"name":"Name 1","description":"Description 1"}}', @response.body
162
- end
163
-
164
176
  def test_render_using_default_root
165
177
  get :render_using_default_adapter_root
166
178
 
167
179
  expected = {
168
180
  data: {
169
- name: "Name 1",
170
- description: "Description 1",
171
181
  id: assigns(:profile).id.to_s,
172
- type: "profiles"
182
+ type: "profiles",
183
+ attributes: {
184
+ name: "Name 1",
185
+ description: "Description 1"
186
+ }
173
187
  }
174
188
  }
175
189
 
@@ -182,10 +196,12 @@ module ActionController
182
196
 
183
197
  expected = {
184
198
  data: {
185
- name: "Name 1",
186
- description: "Description 1",
187
199
  id: assigns(:profile).id.to_s,
188
- type: "profiles"
200
+ type: "profiles",
201
+ attributes: {
202
+ name: "Name 1",
203
+ description: "Description 1"
204
+ }
189
205
  }
190
206
  }
191
207
 
@@ -217,10 +233,12 @@ module ActionController
217
233
  expected = {
218
234
  data: [
219
235
  {
220
- name: "Name 1",
221
- description: "Description 1",
222
236
  id: assigns(:profiles).first.id.to_s,
223
- type: "profiles"
237
+ type: "profiles",
238
+ attributes: {
239
+ name: "Name 1",
240
+ description: "Description 1"
241
+ }
224
242
  }
225
243
  ],
226
244
  meta: {
@@ -319,13 +337,13 @@ module ActionController
319
337
  response = JSON.parse(@response.body)
320
338
 
321
339
  expected_return = {
340
+ "id"=>1,
341
+ "time"=>DateTime.now.to_s,
322
342
  "post" => {
323
343
  "id"=>1,
324
344
  "title"=>"New Post",
325
345
  "body"=>"Body"
326
- },
327
- "id"=>1,
328
- "time"=>DateTime.now.to_s
346
+ }
329
347
  }
330
348
 
331
349
  assert_equal 'application/json', @response.content_type