active_model_serializers 0.10.3 → 0.10.4

Sign up to get free protection for your applications and to get access to all the features.
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