active_model_serializers 0.10.3 → 0.10.4

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c59f59688a0f1097d51eecd56caa45fc9ccec6e0
4
- data.tar.gz: 5907cb2c75b806f2ac46b9457a33e898d10dc4a1
3
+ metadata.gz: c5839aadc9b4688e8c8d2005c19278080683d589
4
+ data.tar.gz: acd53226d78b77f5d13b735fbfc8a3aef06b2827
5
5
  SHA512:
6
- metadata.gz: 540883101bd1555c3697cae38658e773c726a42d8195d6f9f59f928cfe3bf5105c91f3c8fd48c88e83e4d2f288ebd03b07f74d9747ca66fc281d50f82b2983eb
7
- data.tar.gz: 208b3eb1c115cb2c18dce647371e9748576bee1a440c4e7b9edc1e5730e145096bb722c999cd37b620fe03b306dde0da012799d092e11c6377bd1a2c14e990b2
6
+ metadata.gz: f2e27357e980e8886773280a95b411fd6fecc6c9c1cfa9033618e0b2d5cfe9725440d4c143cef062b5087b58679fa45de5769f77c82dc3e16fd28cbe94273526
7
+ data.tar.gz: c08d8d8ec50bdf46dba315157f9cc3f75d3561e242aa70ea1892da527cb830d8558910b9208c5030098458c812081519419a58b43c72fed228fd3c2af80822a7
data/.travis.yml CHANGED
@@ -4,8 +4,8 @@ sudo: false
4
4
 
5
5
  rvm:
6
6
  - 2.1
7
- - 2.2.3
8
- - 2.3.0
7
+ - 2.2.6
8
+ - 2.3.3
9
9
  - ruby-head
10
10
  - jruby-9.0.4.0
11
11
  - jruby-head
data/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ## 0.10.x
2
2
 
3
- ### [master (unreleased)](https://github.com/rails-api/active_model_serializers/compare/v0.10.3...master)
3
+ ### [master (unreleased)](https://github.com/rails-api/active_model_serializers/compare/v0.10.4...master)
4
4
 
5
5
  Breaking changes:
6
6
 
@@ -10,6 +10,13 @@ Fixes:
10
10
 
11
11
  Misc:
12
12
 
13
+ ### [v0.10.4 (2017-01-06)](https://github.com/rails-api/active_model_serializers/compare/v0.10.3...v0.10.4)
14
+
15
+ Misc:
16
+
17
+ - [#2005](https://github.com/rails-api/active_model_serializers/pull/2005) Update jsonapi runtime dependency to 0.1.1.beta6, support Ruby 2.4. (@kofronpi)
18
+ - [#1993](https://github.com/rails-api/active_model_serializers/pull/1993) Swap out KeyTransform for CaseTransform gem for the possibility of native extension use. (@NullVoxPopuli)
19
+
13
20
  ### [v0.10.3 (2016-11-21)](https://github.com/rails-api/active_model_serializers/compare/v0.10.2...v0.10.3)
14
21
 
15
22
  Fixes:
data/README.md CHANGED
@@ -84,8 +84,14 @@ If you'd like to chat, we have a [community slack](http://amserializers.herokuap
84
84
  Thanks!
85
85
 
86
86
  ## Documentation
87
+
88
+ If you're reading this at https://github.com/rails-api/active_model_serializers you are
89
+ reading documentation for our `master`, which may include features that have not
90
+ been released yet. Please see below for the documentation relevant to you.
91
+
87
92
  - [0.10 (master) Documentation](https://github.com/rails-api/active_model_serializers/tree/master)
88
- - [![API Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/gems/active_model_serializers/0.10.2)
93
+ - [0.10.3 (latest release) Documentation](https://github.com/rails-api/active_model_serializers/tree/v0.10.3)
94
+ - [![API Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/gems/active_model_serializers/0.10.3)
89
95
  - [Guides](docs)
90
96
  - [0.9 (0-9-stable) Documentation](https://github.com/rails-api/active_model_serializers/tree/0-9-stable)
91
97
  - [![API Docs](http://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/github/rails-api/active_model_serializers/0-9-stable)
@@ -156,7 +162,141 @@ serializer = SomeSerializer.new(resource, serializer_options)
156
162
  serializer.attributes
157
163
  serializer.associations
158
164
  ```
159
- See [ARCHITECTURE.md](docs/ARCHITECTURE.md) for more information.
165
+
166
+ ## Architecture
167
+
168
+ This section focuses on architecture the 0.10.x version of ActiveModelSerializers. If you are interested in the architecture of the 0.8 or 0.9 versions,
169
+ please refer to the [0.8 README](https://github.com/rails-api/active_model_serializers/blob/0-8-stable/README.md) or
170
+ [0.9 README](https://github.com/rails-api/active_model_serializers/blob/0-9-stable/README.md).
171
+
172
+ The original design is also available [here](https://github.com/rails-api/active_model_serializers/blob/d72b66d4c5355b0ff0a75a04895fcc4ea5b0c65e/README.textile).
173
+
174
+ ### ActiveModel::Serializer
175
+
176
+ An **`ActiveModel::Serializer`** wraps a [serializable resource](https://github.com/rails/rails/blob/4-2-stable/activemodel/lib/active_model/serialization.rb)
177
+ and exposes an `attributes` method, among a few others.
178
+ It allows you to specify which attributes and associations should be represented in the serializatation of the resource.
179
+ It requires an adapter to transform its attributes into a JSON document; it cannot be serialized itself.
180
+ It may be useful to think of it as a
181
+ [presenter](http://blog.steveklabnik.com/posts/2011-09-09-better-ruby-presenters).
182
+
183
+ #### ActiveModel::CollectionSerializer
184
+
185
+ The **`ActiveModel::CollectionSerializer`** represents a collection of resources as serializers
186
+ and, if there is no serializer, primitives.
187
+
188
+ ### ActiveModelSerializers::Adapter::Base
189
+
190
+ The **`ActiveModelSerializeres::Adapter::Base`** describes the structure of the JSON document generated from a
191
+ serializer. For example, the `Attributes` example represents each serializer as its
192
+ unmodified attributes. The `JsonApi` adapter represents the serializer as a [JSON
193
+ API](http://jsonapi.org/) document.
194
+
195
+ ### ActiveModelSerializers::SerializableResource
196
+
197
+ The **`ActiveModelSerializers::SerializableResource`** acts to coordinate the serializer(s) and adapter
198
+ to an object that responds to `to_json`, and `as_json`. It is used in the controller to
199
+ encapsulate the serialization resource when rendered. However, it can also be used on its own
200
+ to serialize a resource outside of a controller, as well.
201
+
202
+ ### Primitive handling
203
+
204
+ Definitions: A primitive is usually a String or Array. There is no serializer
205
+ defined for them; they will be serialized when the resource is converted to JSON (`as_json` or
206
+ `to_json`). (The below also applies for any object with no serializer.)
207
+
208
+ - ActiveModelSerializers doesn't handle primitives passed to `render json:` at all.
209
+
210
+ Internally, if no serializer can be found in the controller, the resource is not decorated by
211
+ ActiveModelSerializers.
212
+
213
+ - However, when a primitive value is an attribute or in a collection, it is not modified.
214
+
215
+ When serializing a collection and the collection serializer (CollectionSerializer) cannot
216
+ identify a serializer for a resource in its collection, it throws [`:no_serializer`](https://github.com/rails-api/active_model_serializers/issues/1191#issuecomment-142327128).
217
+ For example, when caught by `Reflection#build_association`, and the association value is set directly:
218
+
219
+ ```ruby
220
+ reflection_options[:virtual_value] = association_value.try(:as_json) || association_value
221
+ ```
222
+
223
+ (which is called by the adapter as `serializer.associations(*)`.)
224
+
225
+ ### How options are parsed
226
+
227
+ High-level overview:
228
+
229
+ - For a **collection**
230
+ - `:serializer` specifies the collection serializer and
231
+ - `:each_serializer` specifies the serializer for each resource in the collection.
232
+ - For a **single resource**, the `:serializer` option is the resource serializer.
233
+ - Options are partitioned in serializer options and adapter options. Keys for adapter options are specified by
234
+ [`ADAPTER_OPTION_KEYS`](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model_serializers/serializable_resource.rb#L5).
235
+ The remaining options are serializer options.
236
+
237
+ Details:
238
+
239
+ 1. **ActionController::Serialization**
240
+ 1. `serializable_resource = ActiveModelSerializers::SerializableResource.new(resource, options)`
241
+ 1. `options` are partitioned into `adapter_opts` and everything else (`serializer_opts`).
242
+ The `adapter_opts` keys are defined in [`ActiveModelSerializers::SerializableResource::ADAPTER_OPTION_KEYS`](lib/active_model_serializers/serializable_resource.rb#L5).
243
+ 1. **ActiveModelSerializers::SerializableResource**
244
+ 1. `if serializable_resource.serializer?` (there is a serializer for the resource, and an adapter is used.)
245
+ - Where `serializer?` is `use_adapter? && !!(serializer)`
246
+ - Where `use_adapter?`: 'True when no explicit adapter given, or explicit value is truthy (non-nil);
247
+ False when explicit adapter is falsy (nil or false)'
248
+ - Where `serializer`:
249
+ 1. from explicit `:serializer` option, else
250
+ 2. implicitly from resource `ActiveModel::Serializer.serializer_for(resource)`
251
+ 1. A side-effect of checking `serializer` is:
252
+ - The `:serializer` option is removed from the serializer_opts hash
253
+ - If the `:each_serializer` option is present, it is removed from the serializer_opts hash and set as the `:serializer` option
254
+ 1. The serializer and adapter are created as
255
+ 1. `serializer_instance = serializer.new(resource, serializer_opts)`
256
+ 2. `adapter_instance = ActiveModel::Serializer::Adapter.create(serializer_instance, adapter_opts)`
257
+ 1. **ActiveModel::Serializer::CollectionSerializer#new**
258
+ 1. If the `serializer_instance` was a `CollectionSerializer` and the `:serializer` serializer_opts
259
+ is present, then [that serializer is passed into each resource](https://github.com/rails-api/active_model_serializers/blob/a54d237e2828fe6bab1ea5dfe6360d4ecc8214cd/lib/active_model/serializer/array_serializer.rb#L14-L16).
260
+ 1. **ActiveModel::Serializer#attributes** is used by the adapter to get the attributes for
261
+ resource as defined by the serializer.
262
+
263
+ (In Rails, the `options` are also passed to the `as_json(options)` or `to_json(options)`
264
+ methods on the resource serialization by the Rails JSON renderer. They are, therefore, important
265
+ to know about, but not part of ActiveModelSerializers.)
266
+
267
+ ### What does a 'serializable resource' look like?
268
+
269
+ - An `ActiveRecord::Base` object.
270
+ - Any Ruby object that passes the
271
+ [Lint](http://www.rubydoc.info/github/rails-api/active_model_serializers/ActiveModel/Serializer/Lint/Tests)
272
+ [code](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model/serializer/lint.rb).
273
+
274
+ ActiveModelSerializers provides a
275
+ [`ActiveModelSerializers::Model`](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model_serializers/model.rb),
276
+ which is a simple serializable PORO (Plain-Old Ruby Object).
277
+
278
+ `ActiveModelSerializers::Model` may be used either as a reference implementation, or in production code.
279
+
280
+ ```ruby
281
+ class MyModel < ActiveModelSerializers::Model
282
+ attr_accessor :id, :name, :level
283
+ end
284
+ ```
285
+
286
+ The default serializer for `MyModel` would be `MyModelSerializer` whether MyModel is an
287
+ ActiveRecord::Base object or not.
288
+
289
+ Outside of the controller the rules are **exactly** the same as for records. For example:
290
+
291
+ ```ruby
292
+ render json: MyModel.new(level: 'awesome'), adapter: :json
293
+ ```
294
+
295
+ would be serialized the same as
296
+
297
+ ```ruby
298
+ ActiveModelSerializers::SerializableResource.new(MyModel.new(level: 'awesome'), adapter: :json).as_json
299
+ ```
160
300
 
161
301
  ## Semantic Versioning
162
302
 
@@ -42,7 +42,8 @@ Gem::Specification.new do |spec|
42
42
  # 'minitest'
43
43
  # 'thread_safe'
44
44
 
45
- spec.add_runtime_dependency 'jsonapi', '0.1.1.beta2'
45
+ spec.add_runtime_dependency 'jsonapi', '0.1.1.beta6'
46
+ spec.add_runtime_dependency 'case_transform', '>= 0.2'
46
47
 
47
48
  spec.add_development_dependency 'activerecord', rails_versions
48
49
  # arel
data/docs/README.md CHANGED
@@ -18,7 +18,6 @@ This is the documentation of ActiveModelSerializers, it's focused on the **0.10.
18
18
  - JSON API
19
19
  - [Schema](jsonapi/schema.md)
20
20
  - [Errors](jsonapi/errors.md)
21
- - [ARCHITECTURE](ARCHITECTURE.md)
22
21
 
23
22
  ## How to
24
23
 
@@ -48,26 +48,11 @@ render json: @posts, serializer: CollectionSerializer, each_serializer: PostPrev
48
48
 
49
49
  ## Serializing non-ActiveRecord objects
50
50
 
51
- All serializable resources must pass the
52
- [ActiveModel::Serializer::Lint::Tests](../../lib/active_model/serializer/lint.rb#L17).
53
-
54
- See the ActiveModelSerializers::Model for a base class that implements the full
55
- API for a plain-old Ruby object (PORO).
51
+ See [README](../../README.md#what-does-a-serializable-resource-look-like)
56
52
 
57
53
  ## SerializableResource options
58
54
 
59
- The `options` hash passed to `render` or `ActiveModelSerializers::SerializableResource.new(resource, options)`
60
- are partitioned into `serializer_opts` and `adapter_opts`. `adapter_opts` are passed to new Adapters;
61
- `serializer_opts` are passed to new Serializers.
62
-
63
- The `adapter_opts` are specified in [ActiveModelSerializers::SerializableResource::ADAPTER_OPTIONS](../../lib/active_model_serializers/serializable_resource.rb#L5).
64
- The `serializer_opts` are the remaining options.
65
-
66
- (In Rails, the `options` are also passed to the `as_json(options)` or `to_json(options)`
67
- methods on the resource serialization by the Rails JSON renderer. They are, therefore, important
68
- to know about, but not part of ActiveModelSerializers.)
69
-
70
- See [ARCHITECTURE](../ARCHITECTURE.md) for more information.
55
+ See [README](../../README.md#activemodelserializersserializableresource)
71
56
 
72
57
  ### adapter_opts
73
58
 
@@ -37,7 +37,7 @@ class Api::V1::UserSerializer < ActiveModel::Serializer
37
37
  end
38
38
  ```
39
39
 
40
- This will resilt in (example is in jsonapi adapter):
40
+ This will result in (example is in JSONAPI adapter):
41
41
  ```json
42
42
  {
43
43
  "data": {
@@ -69,7 +69,7 @@ class Api::V1::UserSerializer < ActiveModel::Serializer
69
69
  end
70
70
  ```
71
71
 
72
- This will resilt in (example is in jsonapi adapter):
72
+ This will result in (example is in JSONAPI adapter):
73
73
  ```json
74
74
  {
75
75
  "data": {
@@ -66,7 +66,7 @@ module ActiveModel
66
66
  end
67
67
 
68
68
  # @api private
69
- # maps attribute value to explict key name
69
+ # maps attribute value to explicit key name
70
70
  # @see Serializer::attribute
71
71
  # @see FragmentCache#fragment_serializer
72
72
  def _attributes_keys
@@ -1,5 +1,5 @@
1
1
  module ActiveModel
2
2
  class Serializer
3
- VERSION = '0.10.3'.freeze
3
+ VERSION = '0.10.4'.freeze
4
4
  end
5
5
  end
@@ -1,4 +1,4 @@
1
- require 'active_model_serializers/key_transform'
1
+ require 'case_transform'
2
2
 
3
3
  module ActiveModelSerializers
4
4
  module Adapter
@@ -31,7 +31,7 @@ module ActiveModelSerializers
31
31
  # @param options [Object] serializable resource options
32
32
  # @return [Symbol] the default transform for the adapter
33
33
  def self.transform_key_casing!(value, options)
34
- KeyTransform.send(transform(options), value)
34
+ CaseTransform.send(transform(options), value)
35
35
  end
36
36
 
37
37
  def self.cache_key
@@ -205,7 +205,7 @@ module ActiveModelSerializers
205
205
  # @api private
206
206
  def transform_keys(hash, options)
207
207
  transform = options[:key_transform] || :underscore
208
- KeyTransform.send(transform, hash)
208
+ CaseTransform.send(transform, hash)
209
209
  end
210
210
  end
211
211
  end
@@ -14,10 +14,10 @@ module ActionController
14
14
  { source: { pointer: '/data/attributes/id' }, detail: 'must be a uuid' }
15
15
  ]
16
16
  }.to_json
17
- assert_equal json_reponse_body.to_json, expected_errors_object
17
+ assert_equal json_response_body.to_json, expected_errors_object
18
18
  end
19
19
 
20
- def json_reponse_body
20
+ def json_response_body
21
21
  JSON.load(@response.body)
22
22
  end
23
23
 
@@ -456,7 +456,7 @@ module ActionController
456
456
  end
457
457
  end
458
458
 
459
- def test_render_event_is_emmited
459
+ def test_render_event_is_emitted
460
460
  subscriber = ::ActiveSupport::Notifications.subscribe('render.active_model_serializers') do |name|
461
461
  @name = name
462
462
  end
@@ -13,7 +13,7 @@ module ActiveModelSerializers
13
13
  assert_equal '/data', pointer
14
14
  end
15
15
 
16
- def test_unkown_data_pointer
16
+ def test_unknown_data_pointer
17
17
  assert_raises(TypeError) do
18
18
  ActiveModelSerializers::JsonPointer.new(:unknown)
19
19
  end
@@ -115,7 +115,8 @@ module ActiveModelSerializers
115
115
  end
116
116
 
117
117
  def test_that_raises_with_a_invalid_json_body
118
- message = 'A JSON text must at least contain two octets!'
118
+ # message changes from JSON gem 2.0.2 to 2.2.0
119
+ message = /A JSON text must at least contain two octets!|unexpected token at ''/
119
120
 
120
121
  get :invalid_json_body
121
122
 
@@ -123,7 +124,7 @@ module ActiveModelSerializers
123
124
  assert_response_schema('custom/show.json')
124
125
  end
125
126
 
126
- assert_equal(message, error.message)
127
+ assert_match(message, error.message)
127
128
  end
128
129
  end
129
130
  end
@@ -25,21 +25,21 @@ adapter = ActiveModelSerializers::Adapter::JsonApi.new(serializer)
25
25
  serialization = adapter.as_json
26
26
 
27
27
  Benchmark.ams('camel', time: time, disable_gc: disable_gc) do
28
- ActiveModelSerializers::KeyTransform.camel(serialization)
28
+ CaseTransform.camel(serialization)
29
29
  end
30
30
 
31
31
  Benchmark.ams('camel_lower', time: time, disable_gc: disable_gc) do
32
- ActiveModelSerializers::KeyTransform.camel_lower(serialization)
32
+ CaseTransform.camel_lower(serialization)
33
33
  end
34
34
 
35
35
  Benchmark.ams('dash', time: time, disable_gc: disable_gc) do
36
- ActiveModelSerializers::KeyTransform.dash(serialization)
36
+ CaseTransform.dash(serialization)
37
37
  end
38
38
 
39
39
  Benchmark.ams('unaltered', time: time, disable_gc: disable_gc) do
40
- ActiveModelSerializers::KeyTransform.unaltered(serialization)
40
+ CaseTransform.unaltered(serialization)
41
41
  end
42
42
 
43
43
  Benchmark.ams('underscore', time: time, disable_gc: disable_gc) do
44
- ActiveModelSerializers::KeyTransform.underscore(serialization)
44
+ CaseTransform.underscore(serialization)
45
45
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_model_serializers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.3
4
+ version: 0.10.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Klabnik
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-11-21 00:00:00.000000000 Z
11
+ date: 2017-01-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -76,14 +76,28 @@ dependencies:
76
76
  requirements:
77
77
  - - '='
78
78
  - !ruby/object:Gem::Version
79
- version: 0.1.1.beta2
79
+ version: 0.1.1.beta6
80
80
  type: :runtime
81
81
  prerelease: false
82
82
  version_requirements: !ruby/object:Gem::Requirement
83
83
  requirements:
84
84
  - - '='
85
85
  - !ruby/object:Gem::Version
86
- version: 0.1.1.beta2
86
+ version: 0.1.1.beta6
87
+ - !ruby/object:Gem::Dependency
88
+ name: case_transform
89
+ requirement: !ruby/object:Gem::Requirement
90
+ requirements:
91
+ - - ">="
92
+ - !ruby/object:Gem::Version
93
+ version: '0.2'
94
+ type: :runtime
95
+ prerelease: false
96
+ version_requirements: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0.2'
87
101
  - !ruby/object:Gem::Dependency
88
102
  name: activerecord
89
103
  requirement: !ruby/object:Gem::Requirement
@@ -260,7 +274,6 @@ files:
260
274
  - bin/bench
261
275
  - bin/bench_regression
262
276
  - bin/serve_benchmark
263
- - docs/ARCHITECTURE.md
264
277
  - docs/README.md
265
278
  - docs/STYLE.md
266
279
  - docs/general/adapters.md
@@ -343,7 +356,6 @@ files:
343
356
  - lib/active_model_serializers/deprecate.rb
344
357
  - lib/active_model_serializers/deserialization.rb
345
358
  - lib/active_model_serializers/json_pointer.rb
346
- - lib/active_model_serializers/key_transform.rb
347
359
  - lib/active_model_serializers/logging.rb
348
360
  - lib/active_model_serializers/lookup_chain.rb
349
361
  - lib/active_model_serializers/model.rb
@@ -376,7 +388,6 @@ files:
376
388
  - test/action_controller/serialization_test.rb
377
389
  - test/active_model_serializers/adapter_for_test.rb
378
390
  - test/active_model_serializers/json_pointer_test.rb
379
- - test/active_model_serializers/key_transform_test.rb
380
391
  - test/active_model_serializers/logging_test.rb
381
392
  - test/active_model_serializers/model_test.rb
382
393
  - test/active_model_serializers/railtie_test_isolated.rb
@@ -503,7 +514,6 @@ test_files:
503
514
  - test/action_controller/serialization_test.rb
504
515
  - test/active_model_serializers/adapter_for_test.rb
505
516
  - test/active_model_serializers/json_pointer_test.rb
506
- - test/active_model_serializers/key_transform_test.rb
507
517
  - test/active_model_serializers/logging_test.rb
508
518
  - test/active_model_serializers/model_test.rb
509
519
  - test/active_model_serializers/railtie_test_isolated.rb
@@ -590,4 +600,3 @@ test_files:
590
600
  - test/support/schemas/simple_json_pointers.json
591
601
  - test/support/serialization_testing.rb
592
602
  - test/test_helper.rb
593
- has_rdoc:
data/docs/ARCHITECTURE.md DELETED
@@ -1,125 +0,0 @@
1
- [Back to Guides](README.md)
2
-
3
- This document focuses on architecture the 0.10.x version of ActiveModelSerializers. If you are interested in the architecture of the 0.8 or 0.9 versions,
4
- please refer to the [0.8 README](https://github.com/rails-api/active_model_serializers/blob/0-8-stable/README.md) or
5
- [0.9 README](https://github.com/rails-api/active_model_serializers/blob/0-9-stable/README.md).
6
-
7
- The original design is also available [here](https://github.com/rails-api/active_model_serializers/blob/d72b66d4c5355b0ff0a75a04895fcc4ea5b0c65e/README.textile).
8
-
9
- # ARCHITECTURE
10
-
11
- An **`ActiveModel::Serializer`** wraps a [serializable resource](https://github.com/rails/rails/blob/4-2-stable/activemodel/lib/active_model/serialization.rb)
12
- and exposes an `attributes` method, among a few others.
13
- It allows you to specify which attributes and associations should be represented in the serializatation of the resource.
14
- It requires an adapter to transform its attributes into a JSON document; it cannot be serialized itself.
15
- It may be useful to think of it as a
16
- [presenter](http://blog.steveklabnik.com/posts/2011-09-09-better-ruby-presenters).
17
-
18
- The **`ActiveModel::CollectionSerializer`** represents a collection of resources as serializers
19
- and, if there is no serializer, primitives.
20
-
21
- The **`ActiveModel::Adapter`** describes the structure of the JSON document generated from a
22
- serializer. For example, the `Attributes` example represents each serializer as its
23
- unmodified attributes. The `JsonApi` adapter represents the serializer as a [JSON
24
- API](http://jsonapi.org/) document.
25
-
26
- The **`ActiveModelSerializers::SerializableResource`** acts to coordinate the serializer(s) and adapter
27
- to an object that responds to `to_json`, and `as_json`. It is used in the controller to
28
- encapsulate the serialization resource when rendered. However, it can also be used on its own
29
- to serialize a resource outside of a controller, as well.
30
-
31
- ## Primitive handling
32
-
33
- Definitions: A primitive is usually a String or Array. There is no serializer
34
- defined for them; they will be serialized when the resource is converted to JSON (`as_json` or
35
- `to_json`). (The below also applies for any object with no serializer.)
36
-
37
- ActiveModelSerializers doesn't handle primitives passed to `render json:` at all.
38
-
39
- However, when a primitive value is an attribute or in a collection,
40
- it is not modified.
41
-
42
- Internally, if no serializer can be found in the controller, the resource is not decorated by
43
- ActiveModelSerializers.
44
-
45
- If the collection serializer (CollectionSerializer) cannot
46
- identify a serializer for a resource in its collection, it throws [`:no_serializer`](https://github.com/rails-api/active_model_serializers/issues/1191#issuecomment-142327128).
47
- For example, when caught by `Reflection#build_association`, the association value is set directly:
48
-
49
- ```ruby
50
- reflection_options[:virtual_value] = association_value.try(:as_json) || association_value
51
- ```
52
-
53
- (which is called by the adapter as `serializer.associations(*)`.)
54
-
55
- ## How options are parsed
56
-
57
- High-level overview:
58
-
59
- - For a collection
60
- - `:serializer` specifies the collection serializer and
61
- - `:each_serializer` specifies the serializer for each resource in the collection.
62
- - For a single resource, the `:serializer` option is the resource serializer.
63
- - Options are partitioned in serializer options and adapter options. Keys for adapter options are specified by
64
- [`ADAPTER_OPTION_KEYS`](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model_serializers/serializable_resource.rb#L5).
65
- The remaining options are serializer options.
66
-
67
- Details:
68
-
69
- 1. **ActionController::Serialization**
70
- 1. `serializable_resource = ActiveModelSerializers::SerializableResource.new(resource, options)`
71
- 1. `options` are partitioned into `adapter_opts` and everything else (`serializer_opts`).
72
- The `adapter_opts` keys are defined in `ActiveModelSerializers::SerializableResource::ADAPTER_OPTION_KEYS`.
73
- 1. **ActiveModelSerializers::SerializableResource**
74
- 1. `if serializable_resource.serializer?` (there is a serializer for the resource, and an adapter is used.)
75
- - Where `serializer?` is `use_adapter? && !!(serializer)`
76
- - Where `use_adapter?`: 'True when no explicit adapter given, or explicit value is truthy (non-nil);
77
- False when explicit adapter is falsy (nil or false)'
78
- - Where `serializer`:
79
- 1. from explicit `:serializer` option, else
80
- 2. implicitly from resource `ActiveModel::Serializer.serializer_for(resource)`
81
- 1. A side-effect of checking `serializer` is:
82
- - The `:serializer` option is removed from the serializer_opts hash
83
- - If the `:each_serializer` option is present, it is removed from the serializer_opts hash and set as the `:serializer` option
84
- 1. The serializer and adapter are created as
85
- 1. `serializer_instance = serializer.new(resource, serializer_opts)`
86
- 2. `adapter_instance = ActiveModel::Serializer::Adapter.create(serializer_instance, adapter_opts)`
87
- 1. **ActiveModel::Serializer::CollectionSerializer#new**
88
- 1. If the `serializer_instance` was a `CollectionSerializer` and the `:serializer` serializer_opts
89
- is present, then [that serializer is passed into each resource](https://github.com/rails-api/active_model_serializers/blob/a54d237e2828fe6bab1ea5dfe6360d4ecc8214cd/lib/active_model/serializer/array_serializer.rb#L14-L16).
90
- 1. **ActiveModel::Serializer#attributes** is used by the adapter to get the attributes for
91
- resource as defined by the serializer.
92
-
93
- ## What does a 'serializable resource' look like?
94
-
95
- - An `ActiveRecord::Base` object.
96
- - Any Ruby object that passes the
97
- [Lint](http://www.rubydoc.info/github/rails-api/active_model_serializers/ActiveModel/Serializer/Lint/Tests)
98
- [code](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model/serializer/lint.rb).
99
-
100
- ActiveModelSerializers provides a
101
- [`ActiveModelSerializers::Model`](https://github.com/rails-api/active_model_serializers/blob/master/lib/active_model_serializers/model.rb),
102
- which is a simple serializable PORO (Plain-Old Ruby Object).
103
-
104
- ActiveModelSerializers::Model may be used either as a template, or in production code.
105
-
106
- ```ruby
107
- class MyModel < ActiveModelSerializers::Model
108
- attr_accessor :id, :name, :level
109
- end
110
- ```
111
-
112
- The default serializer for `MyModel` would be `MyModelSerializer` whether MyModel is an
113
- ActiveRecord::Base object or not.
114
-
115
- Outside of the controller the rules are **exactly** the same as for records. For example:
116
-
117
- ```ruby
118
- render json: MyModel.new(level: 'awesome'), adapter: :json
119
- ```
120
-
121
- would be serialized the same as
122
-
123
- ```ruby
124
- ActiveModelSerializers::SerializableResource.new(MyModel.new(level: 'awesome'), adapter: :json).as_json
125
- ```
@@ -1,74 +0,0 @@
1
- require 'active_support/core_ext/hash/keys'
2
-
3
- module ActiveModelSerializers
4
- module KeyTransform
5
- module_function
6
-
7
- # Transforms values to UpperCamelCase or PascalCase.
8
- #
9
- # @example:
10
- # "some_key" => "SomeKey",
11
- # @see {https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb#L66-L76 ActiveSupport::Inflector.camelize}
12
- def camel(value)
13
- case value
14
- when Array then value.map { |item| camel(item) }
15
- when Hash then value.deep_transform_keys! { |key| camel(key) }
16
- when Symbol then camel(value.to_s).to_sym
17
- when String then value.underscore.camelize
18
- else value
19
- end
20
- end
21
-
22
- # Transforms values to camelCase.
23
- #
24
- # @example:
25
- # "some_key" => "someKey",
26
- # @see {https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb#L66-L76 ActiveSupport::Inflector.camelize}
27
- def camel_lower(value)
28
- case value
29
- when Array then value.map { |item| camel_lower(item) }
30
- when Hash then value.deep_transform_keys! { |key| camel_lower(key) }
31
- when Symbol then camel_lower(value.to_s).to_sym
32
- when String then value.underscore.camelize(:lower)
33
- else value
34
- end
35
- end
36
-
37
- # Transforms values to dashed-case.
38
- # This is the default case for the JsonApi adapter.
39
- #
40
- # @example:
41
- # "some_key" => "some-key",
42
- # @see {https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb#L185-L187 ActiveSupport::Inflector.dasherize}
43
- def dash(value)
44
- case value
45
- when Array then value.map { |item| dash(item) }
46
- when Hash then value.deep_transform_keys! { |key| dash(key) }
47
- when Symbol then dash(value.to_s).to_sym
48
- when String then value.underscore.dasherize
49
- else value
50
- end
51
- end
52
-
53
- # Transforms values to underscore_case.
54
- # This is the default case for deserialization in the JsonApi adapter.
55
- #
56
- # @example:
57
- # "some-key" => "some_key",
58
- # @see {https://github.com/rails/rails/blob/master/activesupport/lib/active_support/inflector/methods.rb#L89-L98 ActiveSupport::Inflector.underscore}
59
- def underscore(value)
60
- case value
61
- when Array then value.map { |item| underscore(item) }
62
- when Hash then value.deep_transform_keys! { |key| underscore(key) }
63
- when Symbol then underscore(value.to_s).to_sym
64
- when String then value.underscore
65
- else value
66
- end
67
- end
68
-
69
- # Returns the value unaltered
70
- def unaltered(value)
71
- value
72
- end
73
- end
74
- end
@@ -1,297 +0,0 @@
1
- require 'test_helper'
2
-
3
- module ActiveModelSerializers
4
- class KeyTransformTest < ActiveSupport::TestCase
5
- def test_camel
6
- obj = Object.new
7
- scenarios = [
8
- {
9
- value: { :"some-key" => 'value' },
10
- expected: { SomeKey: 'value' }
11
- },
12
- {
13
- value: { someKey: 'value' },
14
- expected: { SomeKey: 'value' }
15
- },
16
- {
17
- value: { some_key: 'value' },
18
- expected: { SomeKey: 'value' }
19
- },
20
- {
21
- value: { 'some-key' => 'value' },
22
- expected: { 'SomeKey' => 'value' }
23
- },
24
- {
25
- value: { 'someKey' => 'value' },
26
- expected: { 'SomeKey' => 'value' }
27
- },
28
- {
29
- value: { 'some_key' => 'value' },
30
- expected: { 'SomeKey' => 'value' }
31
- },
32
- {
33
- value: :"some-value",
34
- expected: :SomeValue
35
- },
36
- {
37
- value: :some_value,
38
- expected: :SomeValue
39
- },
40
- {
41
- value: :someValue,
42
- expected: :SomeValue
43
- },
44
- {
45
- value: 'some-value',
46
- expected: 'SomeValue'
47
- },
48
- {
49
- value: 'someValue',
50
- expected: 'SomeValue'
51
- },
52
- {
53
- value: 'some_value',
54
- expected: 'SomeValue'
55
- },
56
- {
57
- value: obj,
58
- expected: obj
59
- },
60
- {
61
- value: nil,
62
- expected: nil
63
- },
64
- {
65
- value: [
66
- { some_value: 'value' }
67
- ],
68
- expected: [
69
- { SomeValue: 'value' }
70
- ]
71
- }
72
- ]
73
- scenarios.each do |s|
74
- result = ActiveModelSerializers::KeyTransform.camel(s[:value])
75
- assert_equal s[:expected], result
76
- end
77
- end
78
-
79
- def test_camel_lower
80
- obj = Object.new
81
- scenarios = [
82
- {
83
- value: { :"some-key" => 'value' },
84
- expected: { someKey: 'value' }
85
- },
86
- {
87
- value: { SomeKey: 'value' },
88
- expected: { someKey: 'value' }
89
- },
90
- {
91
- value: { some_key: 'value' },
92
- expected: { someKey: 'value' }
93
- },
94
- {
95
- value: { 'some-key' => 'value' },
96
- expected: { 'someKey' => 'value' }
97
- },
98
- {
99
- value: { 'SomeKey' => 'value' },
100
- expected: { 'someKey' => 'value' }
101
- },
102
- {
103
- value: { 'some_key' => 'value' },
104
- expected: { 'someKey' => 'value' }
105
- },
106
- {
107
- value: :"some-value",
108
- expected: :someValue
109
- },
110
- {
111
- value: :SomeValue,
112
- expected: :someValue
113
- },
114
- {
115
- value: :some_value,
116
- expected: :someValue
117
- },
118
- {
119
- value: 'some-value',
120
- expected: 'someValue'
121
- },
122
- {
123
- value: 'SomeValue',
124
- expected: 'someValue'
125
- },
126
- {
127
- value: 'some_value',
128
- expected: 'someValue'
129
- },
130
- {
131
- value: obj,
132
- expected: obj
133
- },
134
- {
135
- value: nil,
136
- expected: nil
137
- },
138
- {
139
- value: [
140
- { some_value: 'value' }
141
- ],
142
- expected: [
143
- { someValue: 'value' }
144
- ]
145
- }
146
- ]
147
- scenarios.each do |s|
148
- result = ActiveModelSerializers::KeyTransform.camel_lower(s[:value])
149
- assert_equal s[:expected], result
150
- end
151
- end
152
-
153
- def test_dash
154
- obj = Object.new
155
- scenarios = [
156
- {
157
- value: { some_key: 'value' },
158
- expected: { :"some-key" => 'value' }
159
- },
160
- {
161
- value: { 'some_key' => 'value' },
162
- expected: { 'some-key' => 'value' }
163
- },
164
- {
165
- value: { SomeKey: 'value' },
166
- expected: { :"some-key" => 'value' }
167
- },
168
- {
169
- value: { 'SomeKey' => 'value' },
170
- expected: { 'some-key' => 'value' }
171
- },
172
- {
173
- value: { someKey: 'value' },
174
- expected: { :"some-key" => 'value' }
175
- },
176
- {
177
- value: { 'someKey' => 'value' },
178
- expected: { 'some-key' => 'value' }
179
- },
180
- {
181
- value: :some_value,
182
- expected: :"some-value"
183
- },
184
- {
185
- value: :SomeValue,
186
- expected: :"some-value"
187
- },
188
- {
189
- value: 'SomeValue',
190
- expected: 'some-value'
191
- },
192
- {
193
- value: :someValue,
194
- expected: :"some-value"
195
- },
196
- {
197
- value: 'someValue',
198
- expected: 'some-value'
199
- },
200
- {
201
- value: obj,
202
- expected: obj
203
- },
204
- {
205
- value: nil,
206
- expected: nil
207
- },
208
- {
209
- value: [
210
- { 'some_value' => 'value' }
211
- ],
212
- expected: [
213
- { 'some-value' => 'value' }
214
- ]
215
- }
216
- ]
217
- scenarios.each do |s|
218
- result = ActiveModelSerializers::KeyTransform.dash(s[:value])
219
- assert_equal s[:expected], result
220
- end
221
- end
222
-
223
- def test_underscore
224
- obj = Object.new
225
- scenarios = [
226
- {
227
- value: { :"some-key" => 'value' },
228
- expected: { some_key: 'value' }
229
- },
230
- {
231
- value: { 'some-key' => 'value' },
232
- expected: { 'some_key' => 'value' }
233
- },
234
- {
235
- value: { SomeKey: 'value' },
236
- expected: { some_key: 'value' }
237
- },
238
- {
239
- value: { 'SomeKey' => 'value' },
240
- expected: { 'some_key' => 'value' }
241
- },
242
- {
243
- value: { someKey: 'value' },
244
- expected: { some_key: 'value' }
245
- },
246
- {
247
- value: { 'someKey' => 'value' },
248
- expected: { 'some_key' => 'value' }
249
- },
250
- {
251
- value: :"some-value",
252
- expected: :some_value
253
- },
254
- {
255
- value: :SomeValue,
256
- expected: :some_value
257
- },
258
- {
259
- value: :someValue,
260
- expected: :some_value
261
- },
262
- {
263
- value: 'some-value',
264
- expected: 'some_value'
265
- },
266
- {
267
- value: 'SomeValue',
268
- expected: 'some_value'
269
- },
270
- {
271
- value: 'someValue',
272
- expected: 'some_value'
273
- },
274
- {
275
- value: obj,
276
- expected: obj
277
- },
278
- {
279
- value: nil,
280
- expected: nil
281
- },
282
- {
283
- value: [
284
- { 'some-value' => 'value' }
285
- ],
286
- expected: [
287
- { 'some_value' => 'value' }
288
- ]
289
- }
290
- ]
291
- scenarios.each do |s|
292
- result = ActiveModelSerializers::KeyTransform.underscore(s[:value])
293
- assert_equal s[:expected], result
294
- end
295
- end
296
- end
297
- end