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