active_model_serializers 0.10.5 → 0.10.6
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/.rubocop.yml +4 -1
- data/CHANGELOG.md +16 -2
- data/README.md +2 -2
- data/Rakefile +1 -30
- data/active_model_serializers.gemspec +1 -1
- data/bin/rubocop +38 -0
- data/docs/general/adapters.md +25 -9
- data/docs/general/getting_started.md +1 -1
- data/docs/general/rendering.md +18 -4
- data/docs/general/serializers.md +21 -2
- data/docs/howto/add_pagination_links.md +1 -1
- data/docs/integrations/ember-and-json-api.md +3 -0
- data/lib/active_model/serializer.rb +252 -74
- data/lib/active_model/serializer/association.rb +51 -14
- data/lib/active_model/serializer/belongs_to_reflection.rb +5 -1
- data/lib/active_model/serializer/concerns/caching.rb +29 -21
- data/lib/active_model/serializer/has_many_reflection.rb +4 -1
- data/lib/active_model/serializer/has_one_reflection.rb +1 -1
- data/lib/active_model/serializer/lazy_association.rb +95 -0
- data/lib/active_model/serializer/reflection.rb +119 -75
- data/lib/active_model/serializer/version.rb +1 -1
- data/lib/active_model_serializers/adapter/json_api.rb +30 -17
- data/lib/active_model_serializers/adapter/json_api/relationship.rb +38 -9
- data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +9 -0
- data/lib/active_model_serializers/model.rb +5 -4
- data/lib/tasks/rubocop.rake +53 -0
- data/test/action_controller/adapter_selector_test.rb +2 -2
- data/test/serializers/associations_test.rb +64 -31
- data/test/serializers/reflection_test.rb +427 -0
- metadata +9 -12
- data/lib/active_model/serializer/collection_reflection.rb +0 -7
- data/lib/active_model/serializer/concerns/associations.rb +0 -102
- data/lib/active_model/serializer/concerns/attributes.rb +0 -82
- data/lib/active_model/serializer/concerns/configuration.rb +0 -59
- data/lib/active_model/serializer/concerns/links.rb +0 -35
- data/lib/active_model/serializer/concerns/meta.rb +0 -29
- data/lib/active_model/serializer/concerns/type.rb +0 -25
- data/lib/active_model/serializer/singular_reflection.rb +0 -7
|
@@ -1,34 +1,71 @@
|
|
|
1
|
+
require 'active_model/serializer/lazy_association'
|
|
2
|
+
|
|
1
3
|
module ActiveModel
|
|
2
4
|
class Serializer
|
|
3
5
|
# This class holds all information about serializer's association.
|
|
4
6
|
#
|
|
5
|
-
# @
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
# @api private
|
|
8
|
+
Association = Struct.new(:reflection, :association_options) do
|
|
9
|
+
attr_reader :lazy_association
|
|
10
|
+
delegate :object, :include_data?, :virtual_value, :collection?, to: :lazy_association
|
|
11
|
+
|
|
12
|
+
def initialize(*)
|
|
13
|
+
super
|
|
14
|
+
@lazy_association = LazyAssociation.new(reflection, association_options)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @return [Symbol]
|
|
18
|
+
delegate :name, to: :reflection
|
|
19
|
+
|
|
13
20
|
# @return [Symbol]
|
|
14
21
|
def key
|
|
15
|
-
|
|
22
|
+
reflection_options.fetch(:key, name)
|
|
16
23
|
end
|
|
17
24
|
|
|
18
|
-
# @return [
|
|
19
|
-
def
|
|
20
|
-
|
|
25
|
+
# @return [True,False]
|
|
26
|
+
def key?
|
|
27
|
+
reflection_options.key?(:key)
|
|
21
28
|
end
|
|
22
29
|
|
|
23
30
|
# @return [Hash]
|
|
24
31
|
def links
|
|
25
|
-
|
|
32
|
+
reflection_options.fetch(:links) || {}
|
|
26
33
|
end
|
|
27
34
|
|
|
28
35
|
# @return [Hash, nil]
|
|
36
|
+
# This gets mutated, so cannot use the cached reflection_options
|
|
29
37
|
def meta
|
|
30
|
-
options[:meta]
|
|
38
|
+
reflection.options[:meta]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def belongs_to?
|
|
42
|
+
reflection.foreign_key_on == :self
|
|
31
43
|
end
|
|
44
|
+
|
|
45
|
+
def polymorphic?
|
|
46
|
+
true == reflection_options[:polymorphic]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# @api private
|
|
50
|
+
def serializable_hash(adapter_options, adapter_instance)
|
|
51
|
+
association_serializer = lazy_association.serializer
|
|
52
|
+
return virtual_value if virtual_value
|
|
53
|
+
association_object = association_serializer && association_serializer.object
|
|
54
|
+
return unless association_object
|
|
55
|
+
|
|
56
|
+
serialization = association_serializer.serializable_hash(adapter_options, {}, adapter_instance)
|
|
57
|
+
|
|
58
|
+
if polymorphic? && serialization
|
|
59
|
+
polymorphic_type = association_object.class.name.underscore
|
|
60
|
+
serialization = { type: polymorphic_type, polymorphic_type.to_sym => serialization }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
serialization
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
delegate :reflection_options, to: :lazy_association
|
|
32
69
|
end
|
|
33
70
|
end
|
|
34
71
|
end
|
|
@@ -40,9 +40,9 @@ module ActiveModel
|
|
|
40
40
|
|
|
41
41
|
module ClassMethods
|
|
42
42
|
def inherited(base)
|
|
43
|
-
super
|
|
44
43
|
caller_line = caller[1]
|
|
45
44
|
base._cache_digest_file_path = caller_line
|
|
45
|
+
super
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
def _cache_digest
|
|
@@ -68,6 +68,18 @@ module ActiveModel
|
|
|
68
68
|
_cache_options && _cache_options[:skip_digest]
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
+
# @api private
|
|
72
|
+
# maps attribute value to explicit key name
|
|
73
|
+
# @see Serializer::attribute
|
|
74
|
+
# @see Serializer::fragmented_attributes
|
|
75
|
+
def _attributes_keys
|
|
76
|
+
_attributes_data
|
|
77
|
+
.each_with_object({}) do |(key, attr), hash|
|
|
78
|
+
next if key == attr.name
|
|
79
|
+
hash[attr.name] = { key: key }
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
71
83
|
def fragmented_attributes
|
|
72
84
|
cached = _cache_only ? _cache_only : _attributes - _cache_except
|
|
73
85
|
cached = cached.map! { |field| _attributes_keys.fetch(field, field) }
|
|
@@ -158,6 +170,7 @@ module ActiveModel
|
|
|
158
170
|
|
|
159
171
|
# Read cache from cache_store
|
|
160
172
|
# @return [Hash]
|
|
173
|
+
# Used in CollectionSerializer to set :cached_attributes
|
|
161
174
|
def cache_read_multi(collection_serializer, adapter_instance, include_directive)
|
|
162
175
|
return {} if ActiveModelSerializers.config.cache_store.blank?
|
|
163
176
|
|
|
@@ -180,12 +193,14 @@ module ActiveModel
|
|
|
180
193
|
cache_keys << object_cache_key(serializer, adapter_instance)
|
|
181
194
|
|
|
182
195
|
serializer.associations(include_directive).each do |association|
|
|
183
|
-
|
|
184
|
-
|
|
196
|
+
# TODO(BF): Process relationship without evaluating lazy_association
|
|
197
|
+
association_serializer = association.lazy_association.serializer
|
|
198
|
+
if association_serializer.respond_to?(:each)
|
|
199
|
+
association_serializer.each do |sub_serializer|
|
|
185
200
|
cache_keys << object_cache_key(sub_serializer, adapter_instance)
|
|
186
201
|
end
|
|
187
202
|
else
|
|
188
|
-
cache_keys << object_cache_key(
|
|
203
|
+
cache_keys << object_cache_key(association_serializer, adapter_instance)
|
|
189
204
|
end
|
|
190
205
|
end
|
|
191
206
|
end
|
|
@@ -203,23 +218,18 @@ module ActiveModel
|
|
|
203
218
|
|
|
204
219
|
### INSTANCE METHODS
|
|
205
220
|
def fetch_attributes(fields, cached_attributes, adapter_instance)
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
attributes(fields, true)
|
|
211
|
-
end
|
|
221
|
+
key = cache_key(adapter_instance)
|
|
222
|
+
cached_attributes.fetch(key) do
|
|
223
|
+
fetch(adapter_instance, serializer_class._cache_options, key) do
|
|
224
|
+
attributes(fields, true)
|
|
212
225
|
end
|
|
213
|
-
elsif serializer_class.fragment_cache_enabled?
|
|
214
|
-
fetch_attributes_fragment(adapter_instance, cached_attributes)
|
|
215
|
-
else
|
|
216
|
-
attributes(fields, true)
|
|
217
226
|
end
|
|
218
227
|
end
|
|
219
228
|
|
|
220
|
-
def fetch(adapter_instance, cache_options = serializer_class._cache_options)
|
|
229
|
+
def fetch(adapter_instance, cache_options = serializer_class._cache_options, key = nil)
|
|
221
230
|
if serializer_class.cache_store
|
|
222
|
-
|
|
231
|
+
key ||= cache_key(adapter_instance)
|
|
232
|
+
serializer_class.cache_store.fetch(key, cache_options) do
|
|
223
233
|
yield
|
|
224
234
|
end
|
|
225
235
|
else
|
|
@@ -230,7 +240,6 @@ module ActiveModel
|
|
|
230
240
|
# 1. Determine cached fields from serializer class options
|
|
231
241
|
# 2. Get non_cached_fields and fetch cache_fields
|
|
232
242
|
# 3. Merge the two hashes using adapter_instance#fragment_cache
|
|
233
|
-
# rubocop:disable Metrics/AbcSize
|
|
234
243
|
def fetch_attributes_fragment(adapter_instance, cached_attributes = {})
|
|
235
244
|
serializer_class._cache_options ||= {}
|
|
236
245
|
serializer_class._cache_options[:key] = serializer_class._cache_key if serializer_class._cache_key
|
|
@@ -239,22 +248,21 @@ module ActiveModel
|
|
|
239
248
|
non_cached_fields = fields[:non_cached].dup
|
|
240
249
|
non_cached_hash = attributes(non_cached_fields, true)
|
|
241
250
|
include_directive = JSONAPI::IncludeDirective.new(non_cached_fields - non_cached_hash.keys)
|
|
242
|
-
non_cached_hash.merge!
|
|
251
|
+
non_cached_hash.merge! associations_hash({}, { include_directive: include_directive }, adapter_instance)
|
|
243
252
|
|
|
244
253
|
cached_fields = fields[:cached].dup
|
|
245
254
|
key = cache_key(adapter_instance)
|
|
246
255
|
cached_hash =
|
|
247
256
|
cached_attributes.fetch(key) do
|
|
248
|
-
|
|
257
|
+
fetch(adapter_instance, serializer_class._cache_options, key) do
|
|
249
258
|
hash = attributes(cached_fields, true)
|
|
250
259
|
include_directive = JSONAPI::IncludeDirective.new(cached_fields - hash.keys)
|
|
251
|
-
hash.merge!
|
|
260
|
+
hash.merge! associations_hash({}, { include_directive: include_directive }, adapter_instance)
|
|
252
261
|
end
|
|
253
262
|
end
|
|
254
263
|
# Merge both results
|
|
255
264
|
adapter_instance.fragment_cache(cached_hash, non_cached_hash)
|
|
256
265
|
end
|
|
257
|
-
# rubocop:enable Metrics/AbcSize
|
|
258
266
|
|
|
259
267
|
def cache_key(adapter_instance)
|
|
260
268
|
return @cache_key if defined?(@cache_key)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
module ActiveModel
|
|
2
|
+
class Serializer
|
|
3
|
+
# @api private
|
|
4
|
+
LazyAssociation = Struct.new(:reflection, :association_options) do
|
|
5
|
+
REFLECTION_OPTIONS = %i(key links polymorphic meta serializer virtual_value namespace).freeze
|
|
6
|
+
|
|
7
|
+
delegate :collection?, to: :reflection
|
|
8
|
+
|
|
9
|
+
def reflection_options
|
|
10
|
+
@reflection_options ||= reflection.options.dup.reject { |k, _| !REFLECTION_OPTIONS.include?(k) }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def object
|
|
14
|
+
@object ||= reflection.value(
|
|
15
|
+
association_options.fetch(:parent_serializer),
|
|
16
|
+
association_options.fetch(:include_slice)
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
alias_method :eval_reflection_block, :object
|
|
20
|
+
|
|
21
|
+
def include_data?
|
|
22
|
+
eval_reflection_block if reflection.block
|
|
23
|
+
reflection.include_data?(
|
|
24
|
+
association_options.fetch(:include_slice)
|
|
25
|
+
)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @return [ActiveModel::Serializer, nil]
|
|
29
|
+
def serializer
|
|
30
|
+
return @serializer if defined?(@serializer)
|
|
31
|
+
if serializer_class
|
|
32
|
+
serialize_object!(object)
|
|
33
|
+
elsif !object.nil? && !object.instance_of?(Object)
|
|
34
|
+
cached_result[:virtual_value] = object
|
|
35
|
+
end
|
|
36
|
+
@serializer = cached_result[:serializer]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def virtual_value
|
|
40
|
+
cached_result[:virtual_value] || reflection_options[:virtual_value]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def serializer_class
|
|
44
|
+
return @serializer_class if defined?(@serializer_class)
|
|
45
|
+
serializer_for_options = { namespace: namespace }
|
|
46
|
+
serializer_for_options[:serializer] = reflection_options[:serializer] if reflection_options.key?(:serializer)
|
|
47
|
+
@serializer_class = association_options.fetch(:parent_serializer).class.serializer_for(object, serializer_for_options)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
def cached_result
|
|
53
|
+
@cached_result ||= {}
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def serialize_object!(object)
|
|
57
|
+
if collection?
|
|
58
|
+
if (serializer = instantiate_collection_serializer(object)).nil?
|
|
59
|
+
# BUG: per #2027, JSON API resource relationships are only id and type, and hence either
|
|
60
|
+
# *require* a serializer or we need to be a little clever about figuring out the id/type.
|
|
61
|
+
# In either case, returning the raw virtual value will almost always be incorrect.
|
|
62
|
+
#
|
|
63
|
+
# Should be reflection_options[:virtual_value] or adapter needs to figure out what to do
|
|
64
|
+
# with an object that is non-nil and has no defined serializer.
|
|
65
|
+
cached_result[:virtual_value] = object.try(:as_json) || object
|
|
66
|
+
else
|
|
67
|
+
cached_result[:serializer] = serializer
|
|
68
|
+
end
|
|
69
|
+
else
|
|
70
|
+
cached_result[:serializer] = instantiate_serializer(object)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def instantiate_serializer(object)
|
|
75
|
+
serializer_options = association_options.fetch(:parent_serializer_options).except(:serializer)
|
|
76
|
+
serializer_options[:serializer_context_class] = association_options.fetch(:parent_serializer).class
|
|
77
|
+
serializer = reflection_options.fetch(:serializer, nil)
|
|
78
|
+
serializer_options[:serializer] = serializer if serializer
|
|
79
|
+
serializer_class.new(object, serializer_options)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def instantiate_collection_serializer(object)
|
|
83
|
+
serializer = catch(:no_serializer) do
|
|
84
|
+
instantiate_serializer(object)
|
|
85
|
+
end
|
|
86
|
+
serializer
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def namespace
|
|
90
|
+
reflection_options[:namespace] ||
|
|
91
|
+
association_options.fetch(:parent_serializer_options)[:namespace]
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'active_model/serializer/field'
|
|
2
|
+
require 'active_model/serializer/association'
|
|
2
3
|
|
|
3
4
|
module ActiveModel
|
|
4
5
|
class Serializer
|
|
@@ -8,12 +9,26 @@ module ActiveModel
|
|
|
8
9
|
# @example
|
|
9
10
|
# class PostSerializer < ActiveModel::Serializer
|
|
10
11
|
# has_one :author, serializer: AuthorSerializer
|
|
12
|
+
# belongs_to :boss, type: :users, foreign_key: :boss_id
|
|
11
13
|
# has_many :comments
|
|
12
14
|
# has_many :comments, key: :last_comments do
|
|
13
15
|
# object.comments.last(1)
|
|
14
16
|
# end
|
|
15
17
|
# has_many :secret_meta_data, if: :is_admin?
|
|
16
18
|
#
|
|
19
|
+
# has_one :blog do |serializer|
|
|
20
|
+
# meta count: object.roles.count
|
|
21
|
+
# serializer.cached_blog
|
|
22
|
+
# end
|
|
23
|
+
#
|
|
24
|
+
# private
|
|
25
|
+
#
|
|
26
|
+
# def cached_blog
|
|
27
|
+
# cache_store.fetch("cached_blog:#{object.updated_at}") do
|
|
28
|
+
# Blog.find(object.blog_id)
|
|
29
|
+
# end
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
17
32
|
# def is_admin?
|
|
18
33
|
# current_user.admin?
|
|
19
34
|
# end
|
|
@@ -23,52 +38,118 @@ module ActiveModel
|
|
|
23
38
|
# 1) as 'comments' and named 'comments'.
|
|
24
39
|
# 2) as 'object.comments.last(1)' and named 'last_comments'.
|
|
25
40
|
#
|
|
26
|
-
# PostSerializer._reflections
|
|
27
|
-
# #
|
|
28
|
-
# # HasOneReflection.new(:author, serializer: AuthorSerializer),
|
|
29
|
-
# # HasManyReflection.new(:comments)
|
|
30
|
-
# # HasManyReflection.new(:comments, { key: :last_comments }, #<Block>)
|
|
31
|
-
# # HasManyReflection.new(:secret_meta_data, { if: :is_admin? })
|
|
32
|
-
# #
|
|
41
|
+
# PostSerializer._reflections # =>
|
|
42
|
+
# # {
|
|
43
|
+
# # author: HasOneReflection.new(:author, serializer: AuthorSerializer),
|
|
44
|
+
# # comments: HasManyReflection.new(:comments)
|
|
45
|
+
# # last_comments: HasManyReflection.new(:comments, { key: :last_comments }, #<Block>)
|
|
46
|
+
# # secret_meta_data: HasManyReflection.new(:secret_meta_data, { if: :is_admin? })
|
|
47
|
+
# # }
|
|
33
48
|
#
|
|
34
49
|
# So you can inspect reflections in your Adapters.
|
|
35
|
-
#
|
|
36
50
|
class Reflection < Field
|
|
51
|
+
attr_reader :foreign_key, :type
|
|
52
|
+
|
|
37
53
|
def initialize(*)
|
|
38
54
|
super
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
55
|
+
options[:links] = {}
|
|
56
|
+
options[:include_data_setting] = Serializer.config.include_data_default
|
|
57
|
+
options[:meta] = nil
|
|
58
|
+
@type = options.fetch(:type) do
|
|
59
|
+
class_name = options.fetch(:class_name, name.to_s.camelize.singularize)
|
|
60
|
+
class_name.underscore.pluralize.to_sym
|
|
61
|
+
end
|
|
62
|
+
@foreign_key = options.fetch(:foreign_key) do
|
|
63
|
+
if collection?
|
|
64
|
+
"#{name.to_s.singularize}_ids".to_sym
|
|
65
|
+
else
|
|
66
|
+
"#{name}_id".to_sym
|
|
67
|
+
end
|
|
68
|
+
end
|
|
42
69
|
end
|
|
43
70
|
|
|
44
|
-
|
|
45
|
-
|
|
71
|
+
# @api public
|
|
72
|
+
# @example
|
|
73
|
+
# has_one :blog do
|
|
74
|
+
# include_data false
|
|
75
|
+
# link :self, 'a link'
|
|
76
|
+
# link :related, 'another link'
|
|
77
|
+
# link :self, '//example.com/link_author/relationships/bio'
|
|
78
|
+
# id = object.profile.id
|
|
79
|
+
# link :related do
|
|
80
|
+
# "//example.com/profiles/#{id}" if id != 123
|
|
81
|
+
# end
|
|
82
|
+
# link :related do
|
|
83
|
+
# ids = object.likes.map(&:id).join(',')
|
|
84
|
+
# href "//example.com/likes/#{ids}"
|
|
85
|
+
# meta ids: ids
|
|
86
|
+
# end
|
|
87
|
+
# end
|
|
88
|
+
def link(name, value = nil)
|
|
89
|
+
options[:links][name] = block_given? ? Proc.new : value
|
|
46
90
|
:nil
|
|
47
91
|
end
|
|
48
92
|
|
|
49
|
-
|
|
50
|
-
|
|
93
|
+
# @api public
|
|
94
|
+
# @example
|
|
95
|
+
# has_one :blog do
|
|
96
|
+
# include_data false
|
|
97
|
+
# meta(id: object.blog.id)
|
|
98
|
+
# meta liked: object.likes.any?
|
|
99
|
+
# link :self do
|
|
100
|
+
# href object.blog.id.to_s
|
|
101
|
+
# meta(id: object.blog.id)
|
|
102
|
+
# end
|
|
103
|
+
def meta(value = nil)
|
|
104
|
+
options[:meta] = block_given? ? Proc.new : value
|
|
51
105
|
:nil
|
|
52
106
|
end
|
|
53
107
|
|
|
108
|
+
# @api public
|
|
109
|
+
# @example
|
|
110
|
+
# has_one :blog do
|
|
111
|
+
# include_data false
|
|
112
|
+
# link :self, 'a link'
|
|
113
|
+
# link :related, 'another link'
|
|
114
|
+
# end
|
|
115
|
+
#
|
|
116
|
+
# has_one :blog do
|
|
117
|
+
# include_data false
|
|
118
|
+
# link :self, 'a link'
|
|
119
|
+
# link :related, 'another link'
|
|
120
|
+
# end
|
|
121
|
+
#
|
|
122
|
+
# belongs_to :reviewer do
|
|
123
|
+
# meta name: 'Dan Brown'
|
|
124
|
+
# include_data true
|
|
125
|
+
# end
|
|
126
|
+
#
|
|
127
|
+
# has_many :tags, serializer: TagSerializer do
|
|
128
|
+
# link :self, '//example.com/link_author/relationships/tags'
|
|
129
|
+
# include_data :if_sideloaded
|
|
130
|
+
# end
|
|
54
131
|
def include_data(value = true)
|
|
55
|
-
|
|
132
|
+
options[:include_data_setting] = value
|
|
56
133
|
:nil
|
|
57
134
|
end
|
|
58
135
|
|
|
136
|
+
def collection?
|
|
137
|
+
false
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def include_data?(include_slice)
|
|
141
|
+
include_data_setting = options[:include_data_setting]
|
|
142
|
+
case include_data_setting
|
|
143
|
+
when :if_sideloaded then include_slice.key?(name)
|
|
144
|
+
when true then true
|
|
145
|
+
when false then false
|
|
146
|
+
else fail ArgumentError, "Unknown include_data_setting '#{include_data_setting.inspect}'"
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
59
150
|
# @param serializer [ActiveModel::Serializer]
|
|
60
151
|
# @yield [ActiveModel::Serializer]
|
|
61
152
|
# @return [:nil, associated resource or resource collection]
|
|
62
|
-
# @example
|
|
63
|
-
# has_one :blog do |serializer|
|
|
64
|
-
# serializer.cached_blog
|
|
65
|
-
# end
|
|
66
|
-
#
|
|
67
|
-
# def cached_blog
|
|
68
|
-
# cache_store.fetch("cached_blog:#{object.updated_at}") do
|
|
69
|
-
# Blog.find(object.blog_id)
|
|
70
|
-
# end
|
|
71
|
-
# end
|
|
72
153
|
def value(serializer, include_slice)
|
|
73
154
|
@object = serializer.object
|
|
74
155
|
@scope = serializer.scope
|
|
@@ -83,6 +164,11 @@ module ActiveModel
|
|
|
83
164
|
end
|
|
84
165
|
end
|
|
85
166
|
|
|
167
|
+
# @api private
|
|
168
|
+
def foreign_key_on
|
|
169
|
+
:related
|
|
170
|
+
end
|
|
171
|
+
|
|
86
172
|
# Build association. This method is used internally to
|
|
87
173
|
# build serializer's association by its reflection.
|
|
88
174
|
#
|
|
@@ -103,61 +189,19 @@ module ActiveModel
|
|
|
103
189
|
# comments_reflection.build_association(post_serializer, foo: 'bar')
|
|
104
190
|
#
|
|
105
191
|
# @api private
|
|
106
|
-
#
|
|
107
192
|
def build_association(parent_serializer, parent_serializer_options, include_slice = {})
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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
|
|
118
|
-
|
|
119
|
-
if serializer_class
|
|
120
|
-
serializer = catch(:no_serializer) do
|
|
121
|
-
serializer_class.new(
|
|
122
|
-
association_value,
|
|
123
|
-
serializer_options(parent_serializer, parent_serializer_options, reflection_options)
|
|
124
|
-
)
|
|
125
|
-
end
|
|
126
|
-
if serializer.nil?
|
|
127
|
-
reflection_options[:virtual_value] = association_value.try(:as_json) || association_value
|
|
128
|
-
else
|
|
129
|
-
reflection_options[:serializer] = serializer
|
|
130
|
-
end
|
|
131
|
-
elsif !association_value.nil? && !association_value.instance_of?(Object)
|
|
132
|
-
reflection_options[:virtual_value] = association_value
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
block = nil
|
|
136
|
-
Association.new(name, reflection_options, block)
|
|
193
|
+
association_options = {
|
|
194
|
+
parent_serializer: parent_serializer,
|
|
195
|
+
parent_serializer_options: parent_serializer_options,
|
|
196
|
+
include_slice: include_slice
|
|
197
|
+
}
|
|
198
|
+
Association.new(self, association_options)
|
|
137
199
|
end
|
|
138
200
|
|
|
139
201
|
protected
|
|
140
202
|
|
|
203
|
+
# used in instance exec
|
|
141
204
|
attr_accessor :object, :scope
|
|
142
|
-
|
|
143
|
-
private
|
|
144
|
-
|
|
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)
|
|
154
|
-
serializer = reflection_options.fetch(:serializer, nil)
|
|
155
|
-
|
|
156
|
-
serializer_options = parent_serializer_options.except(:serializer)
|
|
157
|
-
serializer_options[:serializer] = serializer if serializer
|
|
158
|
-
serializer_options[:serializer_context_class] = parent_serializer.class
|
|
159
|
-
serializer_options
|
|
160
|
-
end
|
|
161
205
|
end
|
|
162
206
|
end
|
|
163
207
|
end
|