active_model_serializers 0.10.2 → 0.10.3
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 +4 -4
- data/.travis.yml +8 -1
- data/CHANGELOG.md +45 -3
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -1
- data/README.md +5 -2
- data/active_model_serializers.gemspec +2 -2
- data/docs/ARCHITECTURE.md +6 -7
- data/docs/README.md +2 -0
- data/docs/general/caching.md +7 -1
- data/docs/general/configuration_options.md +64 -0
- data/docs/general/rendering.md +35 -1
- data/docs/general/serializers.md +35 -5
- data/docs/howto/add_pagination_links.md +2 -2
- data/docs/howto/add_relationship_links.md +137 -0
- data/docs/howto/add_root_key.md +4 -0
- data/docs/howto/grape_integration.md +42 -0
- data/docs/howto/outside_controller_use.md +9 -2
- data/docs/howto/passing_arbitrary_options.md +2 -2
- data/docs/howto/test.md +2 -0
- data/docs/howto/upgrade_from_0_8_to_0_10.md +265 -0
- data/docs/integrations/ember-and-json-api.md +41 -24
- data/lib/action_controller/serialization.rb +9 -0
- data/lib/active_model/serializer.rb +19 -22
- data/lib/active_model/serializer/association.rb +19 -4
- data/lib/active_model/serializer/collection_serializer.rb +8 -5
- data/lib/active_model/serializer/{associations.rb → concerns/associations.rb} +8 -5
- data/lib/active_model/serializer/{attributes.rb → concerns/attributes.rb} +0 -0
- data/lib/active_model/serializer/{caching.rb → concerns/caching.rb} +5 -1
- data/lib/active_model/serializer/{configuration.rb → concerns/configuration.rb} +24 -1
- data/lib/active_model/serializer/{links.rb → concerns/links.rb} +0 -0
- data/lib/active_model/serializer/{meta.rb → concerns/meta.rb} +0 -0
- data/lib/active_model/serializer/{type.rb → concerns/type.rb} +0 -0
- data/lib/active_model/serializer/reflection.rb +37 -21
- data/lib/active_model/serializer/version.rb +1 -1
- data/lib/active_model_serializers.rb +1 -0
- data/lib/active_model_serializers/adapter/attributes.rb +3 -1
- data/lib/active_model_serializers/adapter/json_api.rb +15 -22
- data/lib/active_model_serializers/adapter/json_api/relationship.rb +30 -19
- data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +23 -9
- data/lib/active_model_serializers/key_transform.rb +4 -0
- data/lib/active_model_serializers/lookup_chain.rb +80 -0
- data/lib/active_model_serializers/model.rb +1 -1
- data/lib/active_model_serializers/serializable_resource.rb +6 -5
- data/lib/generators/rails/serializer_generator.rb +1 -1
- data/test/action_controller/json_api/fields_test.rb +57 -0
- data/test/action_controller/json_api/transform_test.rb +3 -3
- data/test/action_controller/lookup_proc_test.rb +49 -0
- data/test/action_controller/namespace_lookup_test.rb +226 -0
- data/test/active_model_serializers/key_transform_test.rb +32 -0
- data/test/active_model_serializers/model_test.rb +11 -0
- data/test/adapter/attributes_test.rb +43 -0
- data/test/adapter/json/transform_test.rb +1 -1
- data/test/adapter/json_api/fields_test.rb +4 -3
- data/test/adapter/json_api/has_many_test.rb +21 -0
- data/test/adapter/json_api/include_data_if_sideloaded_test.rb +166 -0
- data/test/adapter/json_api/linked_test.rb +24 -6
- data/test/adapter/json_api/links_test.rb +1 -1
- data/test/adapter/json_api/pagination_links_test.rb +17 -2
- data/test/adapter/json_api/relationship_test.rb +309 -73
- data/test/adapter/json_api/resource_identifier_test.rb +20 -0
- data/test/adapter/json_api/transform_test.rb +4 -3
- data/test/benchmark/benchmarking_support.rb +1 -1
- data/test/benchmark/bm_active_record.rb +81 -0
- data/test/benchmark/bm_adapter.rb +38 -0
- data/test/benchmark/bm_caching.rb +1 -1
- data/test/benchmark/bm_lookup_chain.rb +83 -0
- data/test/cache_test.rb +42 -4
- data/test/collection_serializer_test.rb +1 -1
- data/test/fixtures/poro.rb +44 -41
- data/test/generators/serializer_generator_test.rb +22 -5
- data/test/serializers/association_macros_test.rb +3 -2
- data/test/serializers/associations_test.rb +97 -22
- data/test/serializers/attribute_test.rb +1 -1
- data/test/serializers/serializer_for_test.rb +3 -3
- data/test/serializers/serializer_for_with_namespace_test.rb +87 -0
- data/test/support/serialization_testing.rb +16 -0
- data/test/test_helper.rb +1 -0
- metadata +35 -14
- data/test/adapter/json_api/relationships_test.rb +0 -204
@@ -38,19 +38,51 @@ You will also want to set the `key_transform` to `:unaltered` since you will adj
|
|
38
38
|
ActiveModelSerializers.config.key_transform = :unaltered
|
39
39
|
```
|
40
40
|
|
41
|
-
|
41
|
+
In order to properly handle JSON API responses, we need to register a JSON API renderer, like so:
|
42
42
|
|
43
43
|
```ruby
|
44
44
|
# config/initializers/active_model_serializers.rb
|
45
|
-
|
45
|
+
ActiveSupport.on_load(:action_controller) do
|
46
|
+
require 'active_model_serializers/register_jsonapi_renderer'
|
47
|
+
end
|
46
48
|
```
|
49
|
+
Rails also requires your controller to tell it that you accept and generate JSONAPI data. To do that, you use `respond_to` in your controller handlers to tell rails you are consuming and returning jsonapi format data. Without this, Rails will refuse to parse the request body into params. You can add `ActionController::MimeResponds` to your application controller to enable this:
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
class ApplicationController < ActionController::API
|
53
|
+
include ActionController::MimeResponds
|
54
|
+
end
|
55
|
+
```
|
56
|
+
Then, in your controller you can tell rails you're accepting and rendering the jsonapi format:
|
57
|
+
```ruby
|
58
|
+
# POST /post
|
59
|
+
def create
|
60
|
+
@post = Post.new(post_params)
|
61
|
+
respond_to do |format|
|
62
|
+
if @post.save
|
63
|
+
format.jsonapi { render jsonapi: @post, status: :created, location: @post }
|
64
|
+
else
|
65
|
+
format.jsonapi { render jsonapi: @post.errors, status: :unprocessable_entity }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Only allow a trusted parameter "white list" through.
|
71
|
+
def post_params
|
72
|
+
ActiveModelSerializers::Deserialization.jsonapi_parse!(params, only: [:title, :body] )
|
73
|
+
end
|
74
|
+
end
|
75
|
+
```
|
76
|
+
|
47
77
|
|
48
78
|
### Adapter Changes
|
49
79
|
|
50
80
|
```javascript
|
51
81
|
// app/adapters/application.js
|
82
|
+
import Ember from 'ember';
|
52
83
|
import DS from 'ember-data';
|
53
84
|
import ENV from "../config/environment";
|
85
|
+
const { underscore, pluralize } = Ember.String;
|
54
86
|
|
55
87
|
export default DS.JSONAPIAdapter.extend({
|
56
88
|
namespace: 'api',
|
@@ -61,22 +93,10 @@ export default DS.JSONAPIAdapter.extend({
|
|
61
93
|
|
62
94
|
// allows the multiword paths in urls to be underscored
|
63
95
|
pathForType: function(type) {
|
64
|
-
let underscored =
|
65
|
-
return
|
96
|
+
let underscored = underscore(type);
|
97
|
+
return pluralize(underscored);
|
66
98
|
},
|
67
99
|
|
68
|
-
// allows queries to be sent along with a findRecord
|
69
|
-
// hopefully Ember / EmberData will soon have this built in
|
70
|
-
// ember-data issue tracked here:
|
71
|
-
// https://github.com/emberjs/data/issues/3596
|
72
|
-
urlForFindRecord(id, modelName, snapshot) {
|
73
|
-
let url = this._super(...arguments);
|
74
|
-
let query = Ember.get(snapshot, 'adapterOptions.query');
|
75
|
-
if(query) {
|
76
|
-
url += '?' + Ember.$.param(query);
|
77
|
-
}
|
78
|
-
return url;
|
79
|
-
}
|
80
100
|
});
|
81
101
|
```
|
82
102
|
|
@@ -100,22 +120,19 @@ export default DS.JSONAPISerializer.extend({
|
|
100
120
|
|
101
121
|
```
|
102
122
|
|
103
|
-
## Including Nested Resources
|
104
123
|
|
105
|
-
|
106
|
-
The ActiveModelSerializers default for the `include` parameter is to be `nil` meaning that if any associations are defined in your serializer, only the `id` and `type` will be in the `relationships` structure of the JSON API response.
|
107
|
-
For more on `include` usage, see: [The JSON API include examples](./../general/adapters.md#JSON-API)
|
124
|
+
## Including Nested Resources
|
108
125
|
|
109
|
-
|
126
|
+
Ember Data can request related records by using `include`. Below are some examples of how to make Ember Data request the inclusion of related records. For more on `include` usage, see: [The JSON API include examples](./../general/adapters.md#JSON-API)
|
110
127
|
|
111
128
|
```javascript
|
112
|
-
store.findRecord('post', postId, {
|
129
|
+
store.findRecord('post', postId, { include: 'comments' } );
|
113
130
|
```
|
114
|
-
will generate the path
|
131
|
+
which will generate the path /posts/{postId}?include='comments'
|
115
132
|
|
116
133
|
So then in your controller, you'll want to be sure to have something like:
|
117
134
|
```ruby
|
118
|
-
render
|
135
|
+
render jsonapi: @post, include: params[:include]
|
119
136
|
```
|
120
137
|
|
121
138
|
If you want to use `include` on a collection, you'd write something like this:
|
@@ -16,6 +16,12 @@ module ActionController
|
|
16
16
|
included do
|
17
17
|
class_attribute :_serialization_scope
|
18
18
|
self._serialization_scope = :current_user
|
19
|
+
|
20
|
+
attr_writer :namespace_for_serializer
|
21
|
+
end
|
22
|
+
|
23
|
+
def namespace_for_serializer
|
24
|
+
@namespace_for_serializer ||= self.class.parent unless self.class.parent == Object
|
19
25
|
end
|
20
26
|
|
21
27
|
def serialization_scope
|
@@ -30,6 +36,9 @@ module ActionController
|
|
30
36
|
"Please pass 'adapter: false' or see ActiveSupport::SerializableResource.new"
|
31
37
|
options[:adapter] = false
|
32
38
|
end
|
39
|
+
|
40
|
+
options.fetch(:namespace) { options[:namespace] = namespace_for_serializer }
|
41
|
+
|
33
42
|
serializable_resource = ActiveModelSerializers::SerializableResource.new(resource, options)
|
34
43
|
serializable_resource.serialization_scope ||= options.fetch(:scope) { serialization_scope }
|
35
44
|
serializable_resource.serialization_scope_name = options.fetch(:scope_name) { _serialization_scope }
|
@@ -4,15 +4,15 @@ require 'active_model/serializer/collection_serializer'
|
|
4
4
|
require 'active_model/serializer/array_serializer'
|
5
5
|
require 'active_model/serializer/error_serializer'
|
6
6
|
require 'active_model/serializer/errors_serializer'
|
7
|
-
require 'active_model/serializer/associations'
|
8
|
-
require 'active_model/serializer/attributes'
|
9
|
-
require 'active_model/serializer/caching'
|
10
|
-
require 'active_model/serializer/configuration'
|
7
|
+
require 'active_model/serializer/concerns/associations'
|
8
|
+
require 'active_model/serializer/concerns/attributes'
|
9
|
+
require 'active_model/serializer/concerns/caching'
|
10
|
+
require 'active_model/serializer/concerns/configuration'
|
11
|
+
require 'active_model/serializer/concerns/links'
|
12
|
+
require 'active_model/serializer/concerns/meta'
|
13
|
+
require 'active_model/serializer/concerns/type'
|
11
14
|
require 'active_model/serializer/fieldset'
|
12
15
|
require 'active_model/serializer/lint'
|
13
|
-
require 'active_model/serializer/links'
|
14
|
-
require 'active_model/serializer/meta'
|
15
|
-
require 'active_model/serializer/type'
|
16
16
|
|
17
17
|
# ActiveModel::Serializer is an abstract class that is
|
18
18
|
# reified when subclassed to decorate a resource.
|
@@ -44,7 +44,7 @@ module ActiveModel
|
|
44
44
|
elsif resource.respond_to?(:to_ary)
|
45
45
|
config.collection_serializer
|
46
46
|
else
|
47
|
-
options.fetch(:serializer) { get_serializer_for(resource.class) }
|
47
|
+
options.fetch(:serializer) { get_serializer_for(resource.class, options[:namespace]) }
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
@@ -59,17 +59,11 @@ module ActiveModel
|
|
59
59
|
end
|
60
60
|
|
61
61
|
# @api private
|
62
|
-
def self.serializer_lookup_chain_for(klass)
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
serializer_class_name = "#{resource_class_name}Serializer"
|
68
|
-
|
69
|
-
chain.push("#{name}::#{serializer_class_name}") if self != ActiveModel::Serializer
|
70
|
-
chain.push("#{resource_namespace}::#{serializer_class_name}")
|
71
|
-
|
72
|
-
chain
|
62
|
+
def self.serializer_lookup_chain_for(klass, namespace = nil)
|
63
|
+
lookups = ActiveModelSerializers.config.serializer_lookup_chain
|
64
|
+
Array[*lookups].flat_map do |lookup|
|
65
|
+
lookup.call(klass, self, namespace)
|
66
|
+
end.compact
|
73
67
|
end
|
74
68
|
|
75
69
|
# Used to cache serializer name => serializer class
|
@@ -84,11 +78,14 @@ module ActiveModel
|
|
84
78
|
# 1. class name appended with "Serializer"
|
85
79
|
# 2. try again with superclass, if present
|
86
80
|
# 3. nil
|
87
|
-
def self.get_serializer_for(klass)
|
81
|
+
def self.get_serializer_for(klass, namespace = nil)
|
88
82
|
return nil unless config.serializer_lookup_enabled
|
89
|
-
|
83
|
+
|
84
|
+
cache_key = ActiveSupport::Cache.expand_cache_key(klass, namespace)
|
85
|
+
serializers_cache.fetch_or_store(cache_key) do
|
90
86
|
# NOTE(beauby): When we drop 1.9.3 support we can lazify the map for perfs.
|
91
|
-
|
87
|
+
lookup_chain = serializer_lookup_chain_for(klass, namespace)
|
88
|
+
serializer_class = lookup_chain.map(&:safe_constantize).find { |x| x && x < ActiveModel::Serializer }
|
92
89
|
|
93
90
|
if serializer_class
|
94
91
|
serializer_class
|
@@ -1,19 +1,34 @@
|
|
1
1
|
module ActiveModel
|
2
2
|
class Serializer
|
3
|
-
# This class
|
3
|
+
# This class holds all information about serializer's association.
|
4
4
|
#
|
5
5
|
# @attr [Symbol] name
|
6
|
-
# @attr [ActiveModel::Serializer] serializer
|
7
6
|
# @attr [Hash{Symbol => Object}] options
|
7
|
+
# @attr [block]
|
8
8
|
#
|
9
9
|
# @example
|
10
|
-
# Association.new(:comments, CommentSummarySerializer)
|
10
|
+
# Association.new(:comments, { serializer: CommentSummarySerializer })
|
11
11
|
#
|
12
|
-
Association
|
12
|
+
class Association < Field
|
13
13
|
# @return [Symbol]
|
14
14
|
def key
|
15
15
|
options.fetch(:key, name)
|
16
16
|
end
|
17
|
+
|
18
|
+
# @return [ActiveModel::Serializer, nil]
|
19
|
+
def serializer
|
20
|
+
options[:serializer]
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [Hash]
|
24
|
+
def links
|
25
|
+
options.fetch(:links) || {}
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return [Hash, nil]
|
29
|
+
def meta
|
30
|
+
options[:meta]
|
31
|
+
end
|
17
32
|
end
|
18
33
|
end
|
19
34
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module ActiveModel
|
2
2
|
class Serializer
|
3
3
|
class CollectionSerializer
|
4
|
-
NoSerializerError = Class.new(StandardError)
|
5
4
|
include Enumerable
|
6
5
|
delegate :each, to: :@serializers
|
7
6
|
|
@@ -52,7 +51,8 @@ module ActiveModel
|
|
52
51
|
# rubocop:enable Metrics/CyclomaticComplexity
|
53
52
|
|
54
53
|
def paginated?
|
55
|
-
|
54
|
+
ActiveModelSerializers.config.jsonapi_pagination_links_enabled &&
|
55
|
+
object.respond_to?(:current_page) &&
|
56
56
|
object.respond_to?(:total_pages) &&
|
57
57
|
object.respond_to?(:size)
|
58
58
|
end
|
@@ -71,10 +71,13 @@ module ActiveModel
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def serializer_from_resource(resource, serializer_context_class, options)
|
74
|
-
serializer_class = options.fetch(:serializer)
|
74
|
+
serializer_class = options.fetch(:serializer) do
|
75
|
+
serializer_context_class.serializer_for(resource, namespace: options[:namespace])
|
76
|
+
end
|
75
77
|
|
76
|
-
if serializer_class.nil?
|
77
|
-
|
78
|
+
if serializer_class.nil?
|
79
|
+
ActiveModelSerializers.logger.debug "No serializer found for resource: #{resource.inspect}"
|
80
|
+
throw :no_serializer
|
78
81
|
else
|
79
82
|
serializer_class.new(resource, options.except(:serializer))
|
80
83
|
end
|
@@ -13,7 +13,7 @@ module ActiveModel
|
|
13
13
|
included do
|
14
14
|
with_options instance_writer: false, instance_reader: true do |serializer|
|
15
15
|
serializer.class_attribute :_reflections
|
16
|
-
self._reflections ||=
|
16
|
+
self._reflections ||= {}
|
17
17
|
end
|
18
18
|
|
19
19
|
extend ActiveSupport::Autoload
|
@@ -74,7 +74,8 @@ module ActiveModel
|
|
74
74
|
# @api private
|
75
75
|
#
|
76
76
|
def associate(reflection)
|
77
|
-
|
77
|
+
key = reflection.options[:key] || reflection.name
|
78
|
+
self._reflections[key] = reflection
|
78
79
|
end
|
79
80
|
end
|
80
81
|
|
@@ -82,15 +83,17 @@ module ActiveModel
|
|
82
83
|
# +default_include_directive+ config value when not provided)
|
83
84
|
# @return [Enumerator<Association>]
|
84
85
|
#
|
85
|
-
def associations(include_directive = ActiveModelSerializers.default_include_directive)
|
86
|
+
def associations(include_directive = ActiveModelSerializers.default_include_directive, include_slice = nil)
|
87
|
+
include_slice ||= include_directive
|
86
88
|
return unless object
|
87
89
|
|
88
90
|
Enumerator.new do |y|
|
89
|
-
self.class._reflections.each do |reflection|
|
91
|
+
self.class._reflections.values.each do |reflection|
|
90
92
|
next if reflection.excluded?(self)
|
91
93
|
key = reflection.options.fetch(:key, reflection.name)
|
92
94
|
next unless include_directive.key?(key)
|
93
|
-
|
95
|
+
|
96
|
+
y.yield reflection.build_association(self, instance_options, include_slice)
|
94
97
|
end
|
95
98
|
end
|
96
99
|
end
|
File without changes
|
@@ -263,7 +263,11 @@ module ActiveModel
|
|
263
263
|
parts << object_cache_key
|
264
264
|
parts << adapter_instance.cache_key
|
265
265
|
parts << serializer_class._cache_digest unless serializer_class._skip_digest?
|
266
|
-
@cache_key = parts
|
266
|
+
@cache_key = expand_cache_key(parts)
|
267
|
+
end
|
268
|
+
|
269
|
+
def expand_cache_key(parts)
|
270
|
+
ActiveSupport::Cache.expand_cache_key(parts)
|
267
271
|
end
|
268
272
|
|
269
273
|
# Use object's cache_key if available, else derive a key from the object
|
@@ -21,13 +21,36 @@ module ActiveModel
|
|
21
21
|
|
22
22
|
config.default_includes = '*'
|
23
23
|
config.adapter = :attributes
|
24
|
+
config.key_transform = nil
|
25
|
+
config.jsonapi_pagination_links_enabled = true
|
24
26
|
config.jsonapi_resource_type = :plural
|
27
|
+
config.jsonapi_namespace_separator = '-'.freeze
|
25
28
|
config.jsonapi_version = '1.0'
|
26
29
|
config.jsonapi_toplevel_meta = {}
|
27
30
|
# Make JSON API top-level jsonapi member opt-in
|
28
31
|
# ref: http://jsonapi.org/format/#document-top-level
|
29
32
|
config.jsonapi_include_toplevel_object = false
|
30
|
-
config.
|
33
|
+
config.include_data_default = true
|
34
|
+
|
35
|
+
# For configuring how serializers are found.
|
36
|
+
# This should be an array of procs.
|
37
|
+
#
|
38
|
+
# The priority of the output is that the first item
|
39
|
+
# in the evaluated result array will take precedence
|
40
|
+
# over other possible serializer paths.
|
41
|
+
#
|
42
|
+
# i.e.: First match wins.
|
43
|
+
#
|
44
|
+
# @example output
|
45
|
+
# => [
|
46
|
+
# "CustomNamespace::ResourceSerializer",
|
47
|
+
# "ParentSerializer::ResourceSerializer",
|
48
|
+
# "ResourceNamespace::ResourceSerializer" ,
|
49
|
+
# "ResourceSerializer"]
|
50
|
+
#
|
51
|
+
# If CustomNamespace::ResourceSerializer exists, it will be used
|
52
|
+
# for serialization
|
53
|
+
config.serializer_lookup_chain = ActiveModelSerializers::LookupChain::DEFAULT.dup
|
31
54
|
|
32
55
|
config.schema_path = 'test/support/schemas'
|
33
56
|
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -37,7 +37,7 @@ module ActiveModel
|
|
37
37
|
def initialize(*)
|
38
38
|
super
|
39
39
|
@_links = {}
|
40
|
-
@_include_data =
|
40
|
+
@_include_data = Serializer.config.include_data_default
|
41
41
|
@_meta = nil
|
42
42
|
end
|
43
43
|
|
@@ -69,17 +69,15 @@ module ActiveModel
|
|
69
69
|
# Blog.find(object.blog_id)
|
70
70
|
# end
|
71
71
|
# end
|
72
|
-
def value(serializer)
|
72
|
+
def value(serializer, include_slice)
|
73
73
|
@object = serializer.object
|
74
74
|
@scope = serializer.scope
|
75
75
|
|
76
|
-
if block
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
serializer.read_attribute_for_serialization(name)
|
82
|
-
end
|
76
|
+
block_value = instance_exec(serializer, &block) if block
|
77
|
+
return unless include_data?(include_slice)
|
78
|
+
|
79
|
+
if block && block_value != :nil
|
80
|
+
block_value
|
83
81
|
else
|
84
82
|
serializer.read_attribute_for_serialization(name)
|
85
83
|
end
|
@@ -88,7 +86,7 @@ module ActiveModel
|
|
88
86
|
# Build association. This method is used internally to
|
89
87
|
# build serializer's association by its reflection.
|
90
88
|
#
|
91
|
-
# @param [Serializer]
|
89
|
+
# @param [Serializer] parent_serializer for given association
|
92
90
|
# @param [Hash{Symbol => Object}] parent_serializer_options
|
93
91
|
#
|
94
92
|
# @example
|
@@ -106,26 +104,36 @@ module ActiveModel
|
|
106
104
|
#
|
107
105
|
# @api private
|
108
106
|
#
|
109
|
-
def build_association(
|
110
|
-
association_value = value(subject)
|
107
|
+
def build_association(parent_serializer, parent_serializer_options, include_slice = {})
|
111
108
|
reflection_options = options.dup
|
112
|
-
|
113
|
-
|
109
|
+
|
110
|
+
# Pass the parent's namespace onto the child serializer
|
111
|
+
reflection_options[:namespace] ||= parent_serializer_options[:namespace]
|
112
|
+
|
113
|
+
association_value = value(parent_serializer, include_slice)
|
114
|
+
serializer_class = parent_serializer.class.serializer_for(association_value, reflection_options)
|
115
|
+
reflection_options[:include_data] = include_data?(include_slice)
|
116
|
+
reflection_options[:links] = @_links
|
117
|
+
reflection_options[:meta] = @_meta
|
114
118
|
|
115
119
|
if serializer_class
|
116
|
-
|
117
|
-
|
120
|
+
serializer = catch(:no_serializer) do
|
121
|
+
serializer_class.new(
|
118
122
|
association_value,
|
119
|
-
serializer_options(
|
123
|
+
serializer_options(parent_serializer, parent_serializer_options, reflection_options)
|
120
124
|
)
|
121
|
-
|
125
|
+
end
|
126
|
+
if serializer.nil?
|
122
127
|
reflection_options[:virtual_value] = association_value.try(:as_json) || association_value
|
128
|
+
else
|
129
|
+
reflection_options[:serializer] = serializer
|
123
130
|
end
|
124
131
|
elsif !association_value.nil? && !association_value.instance_of?(Object)
|
125
132
|
reflection_options[:virtual_value] = association_value
|
126
133
|
end
|
127
134
|
|
128
|
-
|
135
|
+
block = nil
|
136
|
+
Association.new(name, reflection_options, block)
|
129
137
|
end
|
130
138
|
|
131
139
|
protected
|
@@ -134,12 +142,20 @@ module ActiveModel
|
|
134
142
|
|
135
143
|
private
|
136
144
|
|
137
|
-
def
|
145
|
+
def include_data?(include_slice)
|
146
|
+
if @_include_data == :if_sideloaded
|
147
|
+
include_slice.key?(name)
|
148
|
+
else
|
149
|
+
@_include_data
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def serializer_options(parent_serializer, parent_serializer_options, reflection_options)
|
138
154
|
serializer = reflection_options.fetch(:serializer, nil)
|
139
155
|
|
140
156
|
serializer_options = parent_serializer_options.except(:serializer)
|
141
157
|
serializer_options[:serializer] = serializer if serializer
|
142
|
-
serializer_options[:serializer_context_class] =
|
158
|
+
serializer_options[:serializer_context_class] = parent_serializer.class
|
143
159
|
serializer_options
|
144
160
|
end
|
145
161
|
end
|