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/concerns/associations'
8
- require 'active_model/serializer/concerns/attributes'
9
7
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'
14
8
require 'active_model/serializer/fieldset'
15
9
require 'active_model/serializer/lint'
16
10
@@ -23,13 +17,16 @@ class Serializer
23
17
extend ActiveSupport ::Autoload
24
18
autoload :Adapter
25
19
autoload :Null
26
- include Configuration
27
- include Associations
28
- include Attributes
20
+ autoload :Attribute
21
+ autoload :Association
22
+ autoload :Reflection
23
+ autoload :SingularReflection
24
+ autoload :CollectionReflection
25
+ autoload :BelongsToReflection
26
+ autoload :HasOneReflection
27
+ autoload :HasManyReflection
28
+ include ActiveSupport ::Configurable
29
29
include Caching
30
- include Links
31
- include Meta
32
- include Type
33
30
34
31
# @param resource [ActiveRecord::Base, ActiveModelSerializers::Model]
35
32
# @return [ActiveModel::Serializer]
@@ -111,6 +108,200 @@ def self.serialization_adapter_instance
111
108
@serialization_adapter_instance ||= ActiveModelSerializers ::Adapter ::Attributes
112
109
end
113
110
111
+ # Configuration options may also be set in
112
+ # Serializers and Adapters
113
+ config . collection_serializer = ActiveModel ::Serializer ::CollectionSerializer
114
+ config . serializer_lookup_enabled = true
115
+
116
+ # @deprecated Use {#config.collection_serializer=} instead of this. Is
117
+ # compatibilty layer for ArraySerializer.
118
+ def config . array_serializer = ( collection_serializer )
119
+ self . collection_serializer = collection_serializer
120
+ end
121
+
122
+ # @deprecated Use {#config.collection_serializer} instead of this. Is
123
+ # compatibilty layer for ArraySerializer.
124
+ def config . array_serializer
125
+ collection_serializer
126
+ end
127
+
128
+ config . default_includes = '*'
129
+ config . adapter = :attributes
130
+ config . key_transform = nil
131
+ config . jsonapi_pagination_links_enabled = true
132
+ config . jsonapi_resource_type = :plural
133
+ config . jsonapi_namespace_separator = '-' . freeze
134
+ config . jsonapi_version = '1.0'
135
+ config . jsonapi_toplevel_meta = { }
136
+ # Make JSON API top-level jsonapi member opt-in
137
+ # ref: http://jsonapi.org/format/#document-top-level
138
+ config . jsonapi_include_toplevel_object = false
139
+ config . include_data_default = true
140
+
141
+ # For configuring how serializers are found.
142
+ # This should be an array of procs.
143
+ #
144
+ # The priority of the output is that the first item
145
+ # in the evaluated result array will take precedence
146
+ # over other possible serializer paths.
147
+ #
148
+ # i.e.: First match wins.
149
+ #
150
+ # @example output
151
+ # => [
152
+ # "CustomNamespace::ResourceSerializer",
153
+ # "ParentSerializer::ResourceSerializer",
154
+ # "ResourceNamespace::ResourceSerializer" ,
155
+ # "ResourceSerializer"]
156
+ #
157
+ # If CustomNamespace::ResourceSerializer exists, it will be used
158
+ # for serialization
159
+ config . serializer_lookup_chain = ActiveModelSerializers ::LookupChain ::DEFAULT . dup
160
+
161
+ config . schema_path = 'test/support/schemas'
162
+
163
+ with_options instance_writer : false , instance_reader : false do |serializer |
164
+ serializer . class_attribute :_attributes_data # @api private
165
+ self . _attributes_data ||= { }
166
+ end
167
+ with_options instance_writer : false , instance_reader : true do |serializer |
168
+ serializer . class_attribute :_reflections
169
+ self . _reflections ||= { }
170
+ serializer . class_attribute :_links # @api private
171
+ self . _links ||= { }
172
+ serializer . class_attribute :_meta # @api private
173
+ serializer . class_attribute :_type # @api private
174
+ end
175
+
176
+ def self . inherited ( base )
177
+ super
178
+ base . _attributes_data = _attributes_data . dup
179
+ base . _reflections = _reflections . dup
180
+ base . _links = _links . dup
181
+ end
182
+
183
+ # keys of attributes
184
+ # @see Serializer::attribute
185
+ def self . _attributes
186
+ _attributes_data . keys
187
+ end
188
+
189
+ # @example
190
+ # class AdminAuthorSerializer < ActiveModel::Serializer
191
+ # attributes :id, :name, :recent_edits
192
+ def self . attributes ( *attrs )
193
+ attrs = attrs . first if attrs . first . class == Array
194
+
195
+ attrs . each do |attr |
196
+ attribute ( attr )
197
+ end
198
+ end
199
+
200
+ # @example
201
+ # class AdminAuthorSerializer < ActiveModel::Serializer
202
+ # attributes :id, :recent_edits
203
+ # attribute :name, key: :title
204
+ #
205
+ # attribute :full_name do
206
+ # "#{object.first_name} #{object.last_name}"
207
+ # end
208
+ #
209
+ # def recent_edits
210
+ # object.edits.last(5)
211
+ # end
212
+ def self . attribute ( attr , options = { } , &block )
213
+ key = options . fetch ( :key , attr )
214
+ _attributes_data [ key ] = Attribute . new ( attr , options , block )
215
+ end
216
+
217
+ # @api private
218
+ # maps attribute value to explicit key name
219
+ # @see Serializer::attribute
220
+ # @see ActiveModel::Serializer::Caching#fragmented_attributes
221
+ def self . _attributes_keys
222
+ _attributes_data
223
+ . each_with_object ( { } ) do |( key , attr ) , hash |
224
+ next if key == attr . name
225
+ hash [ attr . name ] = { key : key }
226
+ end
227
+ end
228
+
229
+ # @param [Symbol] name of the association
230
+ # @param [Hash<Symbol => any>] options for the reflection
231
+ # @return [void]
232
+ #
233
+ # @example
234
+ # has_many :comments, serializer: CommentSummarySerializer
235
+ #
236
+ def self . has_many ( name , options = { } , &block ) # rubocop:disable Style/PredicateName
237
+ associate ( HasManyReflection . new ( name , options , block ) )
238
+ end
239
+
240
+ # @param [Symbol] name of the association
241
+ # @param [Hash<Symbol => any>] options for the reflection
242
+ # @return [void]
243
+ #
244
+ # @example
245
+ # belongs_to :author, serializer: AuthorSerializer
246
+ #
247
+ def self . belongs_to ( name , options = { } , &block )
248
+ associate ( BelongsToReflection . new ( name , options , block ) )
249
+ end
250
+
251
+ # @param [Symbol] name of the association
252
+ # @param [Hash<Symbol => any>] options for the reflection
253
+ # @return [void]
254
+ #
255
+ # @example
256
+ # has_one :author, serializer: AuthorSerializer
257
+ #
258
+ def self . has_one ( name , options = { } , &block ) # rubocop:disable Style/PredicateName
259
+ associate ( HasOneReflection . new ( name , options , block ) )
260
+ end
261
+
262
+ # Add reflection and define {name} accessor.
263
+ # @param [ActiveModel::Serializer::Reflection] reflection
264
+ # @return [void]
265
+ #
266
+ # @api private
267
+ def self . associate ( reflection )
268
+ key = reflection . options [ :key ] || reflection . name
269
+ self . _reflections [ key ] = reflection
270
+ end
271
+ private_class_method :associate
272
+
273
+ # Define a link on a serializer.
274
+ # @example
275
+ # link(:self) { resource_url(object) }
276
+ # @example
277
+ # link(:self) { "http://example.com/resource/#{object.id}" }
278
+ # @example
279
+ # link :resource, "http://example.com/resource"
280
+ #
281
+ def self . link ( name , value = nil , &block )
282
+ _links [ name ] = block || value
283
+ end
284
+
285
+ # Set the JSON API meta attribute of a serializer.
286
+ # @example
287
+ # class AdminAuthorSerializer < ActiveModel::Serializer
288
+ # meta { stuff: 'value' }
289
+ # @example
290
+ # meta do
291
+ # { comment_count: object.comments.count }
292
+ # end
293
+ def self . meta ( value = nil , &block )
294
+ self . _meta = block || value
295
+ end
296
+
297
+ # Set the JSON API type of a serializer.
298
+ # @example
299
+ # class AdminAuthorSerializer < ActiveModel::Serializer
300
+ # type 'authors'
301
+ def self . type ( type )
302
+ self . _type = type && type . to_s
303
+ end
304
+
114
305
attr_accessor :object , :root , :scope
115
306
116
307
# `scope_name` is set as :current_user by default in the controller.
@@ -131,6 +322,36 @@ def success?
131
322
true
132
323
end
133
324
325
+ # Return the +attributes+ of +object+ as presented
326
+ # by the serializer.
327
+ def attributes ( requested_attrs = nil , reload = false )
328
+ @attributes = nil if reload
329
+ @attributes ||= self . class . _attributes_data . each_with_object ( { } ) do |( key , attr ) , hash |
330
+ next if attr . excluded? ( self )
331
+ next unless requested_attrs . nil? || requested_attrs . include? ( key )
332
+ hash [ key ] = attr . value ( self )
333
+ end
334
+ end
335
+
336
+ # @param [JSONAPI::IncludeDirective] include_directive (defaults to the
337
+ # +default_include_directive+ config value when not provided)
338
+ # @return [Enumerator<Association>]
339
+ #
340
+ def associations ( include_directive = ActiveModelSerializers . default_include_directive , include_slice = nil )
341
+ include_slice ||= include_directive
342
+ return unless object
343
+
344
+ Enumerator . new do |y |
345
+ self . class . _reflections . values . each do |reflection |
346
+ next if reflection . excluded? ( self )
347
+ key = reflection . options . fetch ( :key , reflection . name )
348
+ next unless include_directive . key? ( key )
349
+
350
+ y . yield reflection . build_association ( self , instance_options , include_slice )
351
+ end
352
+ end
353
+ end
354
+
134
355
# @return [Hash] containing the attributes and first level
135
356
# associations, similar to how ActiveModel::Serializers::JSON is used
136
357
# in ActiveRecord::Base.
0 commit comments