Class: ActiveModel::Serializer

Inherits:
Object
  • Object
show all
Extended by:
ActiveModelSerializers::Deprecate, ActiveSupport::Autoload
Includes:
Caching, ActiveSupport::Configurable
Defined in:
lib/active_model/serializer.rb,
lib/active_model/serializer/link.rb,
lib/active_model/serializer/lint.rb,
lib/active_model/serializer/null.rb,
lib/active_model/serializer/field.rb,
lib/active_model/serializer/adapter.rb,
lib/active_model/serializer/version.rb,
lib/active_model/serializer/fieldset.rb,
lib/active_model/serializer/attribute.rb,
lib/active_model/serializer/reflection.rb,
lib/active_model/serializer/association.rb,
lib/active_model/serializer/adapter/base.rb,
lib/active_model/serializer/adapter/json.rb,
lib/active_model/serializer/adapter/null.rb,
lib/active_model/serializer/adapter/json_api.rb,
lib/active_model/serializer/array_serializer.rb,
lib/active_model/serializer/concerns/caching.rb,
lib/active_model/serializer/error_serializer.rb,
lib/active_model/serializer/lazy_association.rb,
lib/active_model/serializer/errors_serializer.rb,
lib/active_model/serializer/adapter/attributes.rb,
lib/active_model/serializer/has_one_reflection.rb,
lib/active_model/serializer/has_many_reflection.rb,
lib/active_model/serializer/belongs_to_reflection.rb,
lib/active_model/serializer/collection_serializer.rb

Direct Known Subclasses

ErrorSerializer, Null

Defined Under Namespace

Modules: Adapter, Caching, Lint Classes: ArraySerializer, Association, Attribute, BelongsToReflection, CollectionSerializer, ErrorSerializer, ErrorsSerializer, Field, Fieldset, HasManyReflection, HasOneReflection, LazyAssociation, Link, Null, Reflection

Constant Summary collapse

SERIALIZABLE_HASH_VALID_KEYS =
[:only, :except, :methods, :include, :root].freeze
VERSION =
'0.10.15'.freeze
UndefinedCacheKey =
Class.new(StandardError)

Constants included from Caching

Caching::CALLER_FILE

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ActiveModelSerializers::Deprecate

delegate_and_deprecate, deprecate

Methods included from Caching

#cache_key, #expand_cache_key, #fetch, #fetch_attributes, #fetch_attributes_fragment, #object_cache_key, #serializer_class

Constructor Details

#initialize(object, options = {}) ⇒ Serializer

‘scope_name` is set as :current_user by default in the controller. If the instance does not have a method named `scope_name`, it defines the method so that it calls the scope.



319
320
321
322
323
324
325
326
327
328
# File 'lib/active_model/serializer.rb', line 319

def initialize(object, options = {})
  self.object = object
  self.instance_options = options
  self.root = instance_options[:root]
  self.scope = instance_options[:scope]

  return if !(scope_name = instance_options[:scope_name]) || respond_to?(scope_name)

  define_singleton_method scope_name, -> { scope }
end

Instance Attribute Details

#objectObject

END SERIALIZER MACROS



314
315
316
# File 'lib/active_model/serializer.rb', line 314

def object
  @object
end

#rootObject

END SERIALIZER MACROS



314
315
316
# File 'lib/active_model/serializer.rb', line 314

def root
  @root
end

#scopeObject

END SERIALIZER MACROS



314
315
316
# File 'lib/active_model/serializer.rb', line 314

def scope
  @scope
end

Class Method Details

._attributesArray<Symbol>

Returns Key names of declared attributes.

Returns:

  • (Array<Symbol>)

    Key names of declared attributes

See Also:

  • Serializer::attribute


197
198
199
# File 'lib/active_model/serializer.rb', line 197

def self._attributes
  _attributes_data.keys
end

.adapterObject

Deprecated



56
57
58
# File 'lib/active_model/serializer.rb', line 56

def self.adapter
  ActiveModelSerializers::Adapter.lookup(config.adapter)
end

.attribute(attr, options = {}, &block) ⇒ Object

Examples:

class AdminAuthorSerializer < ActiveModel::Serializer
  attributes :id, :recent_edits
  attribute :name, key: :title

  attribute :full_name do
    "#{object.first_name} #{object.last_name}"
  end

  def recent_edits
    object.edits.last(5)
  end


226
227
228
229
# File 'lib/active_model/serializer.rb', line 226

def self.attribute(attr, options = {}, &block)
  key = options.fetch(:key, attr)
  _attributes_data[key] = Attribute.new(attr, options, block)
end

.attributes(*attrs) ⇒ Object

Examples:

class AdminAuthorSerializer < ActiveModel::Serializer
  attributes :id, :name, :recent_edits


206
207
208
209
210
211
212
# File 'lib/active_model/serializer.rb', line 206

def self.attributes(*attrs)
  attrs = attrs.first if attrs.first.class == Array

  attrs.each do |attr|
    attribute(attr)
  end
end

.belongs_to(name, options = {}, &block) ⇒ void

This method returns an undefined value.

Examples:

belongs_to :author, serializer: AuthorSerializer

Parameters:

  • name (Symbol)

    of the association

  • options (Hash<Symbol => any>) (defaults to: {})

    for the reflection



249
250
251
# File 'lib/active_model/serializer.rb', line 249

def self.belongs_to(name, options = {}, &block)
  associate(BelongsToReflection.new(name, options, block))
end

.get_serializer_for(klass, namespace = nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Find a serializer from a class and caches the lookup. Preferentially returns:

1. class name appended with "Serializer"
2. try again with superclass, if present
3. nil


84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/active_model/serializer.rb', line 84

def self.get_serializer_for(klass, namespace = nil)
  return nil unless config.serializer_lookup_enabled

  cache_key = ActiveSupport::Cache.expand_cache_key(klass, namespace)
  serializers_cache.fetch_or_store(cache_key) do
    # NOTE(beauby): When we drop 1.9.3 support we can lazify the map for perfs.
    lookup_chain = serializer_lookup_chain_for(klass, namespace)
    serializer_class = lookup_chain.map(&:safe_constantize).find { |x| x && x < ActiveModel::Serializer }

    if serializer_class
      serializer_class
    elsif klass.superclass
      get_serializer_for(klass.superclass, namespace)
    else
      nil # No serializer found
    end
  end
end

.has_many(name, options = {}, &block) ⇒ void

This method returns an undefined value.

Examples:

has_many :comments, serializer: CommentSummarySerializer

Parameters:

  • name (Symbol)

    of the association

  • options (Hash<Symbol => any>) (defaults to: {})

    for the reflection



238
239
240
# File 'lib/active_model/serializer.rb', line 238

def self.has_many(name, options = {}, &block) # rubocop:disable Style/PredicateName
  associate(HasManyReflection.new(name, options, block))
end

.has_one(name, options = {}, &block) ⇒ void

This method returns an undefined value.

Examples:

has_one :author, serializer: AuthorSerializer

Parameters:

  • name (Symbol)

    of the association

  • options (Hash<Symbol => any>) (defaults to: {})

    for the reflection



260
261
262
# File 'lib/active_model/serializer.rb', line 260

def self.has_one(name, options = {}, &block) # rubocop:disable Style/PredicateName
  associate(HasOneReflection.new(name, options, block))
end

.include_directive_from_options(options) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



104
105
106
107
108
109
110
111
112
# File 'lib/active_model/serializer.rb', line 104

def self.include_directive_from_options(options)
  if options[:include_directive]
    options[:include_directive]
  elsif options[:include]
    JSONAPI::IncludeDirective.new(options[:include], allow_wildcard: true)
  else
    ActiveModelSerializers.default_include_directive
  end
end

.inherited(base) ⇒ Object



188
189
190
191
192
193
# File 'lib/active_model/serializer.rb', line 188

def self.inherited(base)
  super
  base._attributes_data = _attributes_data.dup
  base._reflections = _reflections.dup
  base._links = _links.dup
end

Define a link on a serializer.

Examples:

link(:self) { resource_url(object) }
link(:self) { "http://example.com/resource/#{object.id}" }
link :resource, "http://example.com/resource"
link(:callback, if: :internal?), { "http://example.com/callback" }


285
286
287
288
289
290
# File 'lib/active_model/serializer.rb', line 285

def self.link(name, *args, &block)
  options = args.extract_options!
  # For compatibility with the use case of passing link directly as string argument
  # without block, we are creating a wrapping block
  _links[name] = Link.new(name, options, block || ->(_serializer) { args.first })
end

.meta(value = nil, &block) ⇒ Object

Set the JSON API meta attribute of a serializer.

Examples:

class AdminAuthorSerializer < ActiveModel::Serializer
  meta { stuff: 'value' }
meta do
  { comment_count: object.comments.count }
end


300
301
302
# File 'lib/active_model/serializer.rb', line 300

def self.meta(value = nil, &block)
  self._meta = block || value
end

.serialization_adapter_instanceObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



115
116
117
# File 'lib/active_model/serializer.rb', line 115

def self.serialization_adapter_instance
  @serialization_adapter_instance ||= ActiveModelSerializers::Adapter::Attributes
end

.serializer_for(resource_or_class, options = {}) ⇒ ActiveModel::Serializer

Returns Preferentially returns

  1. resource.serializer_class

  2. ArraySerializer when resource is a collection

  3. options

  4. lookup serializer when resource is a Class.

Parameters:

Returns:

  • (ActiveModel::Serializer)

    Preferentially returns

    1. resource.serializer_class

    2. ArraySerializer when resource is a collection

    3. options

    4. lookup serializer when resource is a Class



43
44
45
46
47
48
49
50
51
52
# File 'lib/active_model/serializer.rb', line 43

def self.serializer_for(resource_or_class, options = {})
  if resource_or_class.respond_to?(:serializer_class)
    resource_or_class.serializer_class
  elsif resource_or_class.respond_to?(:to_ary)
    config.collection_serializer
  else
    resource_class = resource_or_class.class == Class ? resource_or_class : resource_or_class.class
    options.fetch(:serializer) { get_serializer_for(resource_class, options[:namespace]) }
  end
end

.serializer_lookup_chain_for(klass, namespace = nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



65
66
67
68
69
70
# File 'lib/active_model/serializer.rb', line 65

def self.serializer_lookup_chain_for(klass, namespace = nil)
  lookups = ActiveModelSerializers.config.serializer_lookup_chain
  Array[*lookups].flat_map do |lookup|
    lookup.call(klass, self, namespace)
  end.compact
end

.serializers_cacheObject

Used to cache serializer name => serializer class when looked up by Serializer.get_serializer_for.



74
75
76
# File 'lib/active_model/serializer.rb', line 74

def self.serializers_cache
  @serializers_cache ||= Concurrent::Map.new
end

.type(type) ⇒ Object

Set the JSON API type of a serializer.

Examples:

class AdminAuthorSerializer < ActiveModel::Serializer
  type 'authors'


308
309
310
# File 'lib/active_model/serializer.rb', line 308

def self.type(type)
  self._type = type && type.to_s
end

Instance Method Details

#as_json(adapter_opts = nil) ⇒ Object

See Also:



380
381
382
# File 'lib/active_model/serializer.rb', line 380

def as_json(adapter_opts = nil)
  serializable_hash(adapter_opts)
end

#associations(include_directive = ActiveModelSerializers.default_include_directive, include_slice = nil) ⇒ Enumerator<Association>

Parameters:

  • include_directive (JSONAPI::IncludeDirective) (defaults to: ActiveModelSerializers.default_include_directive)

    (defaults to the default_include_directive config value when not provided)

Returns:



348
349
350
351
352
353
354
355
356
357
358
359
360
361
# File 'lib/active_model/serializer.rb', line 348

def associations(include_directive = ActiveModelSerializers.default_include_directive, include_slice = nil)
  include_slice ||= include_directive
  return Enumerator.new {} unless object

  Enumerator.new do |y|
    (self.instance_reflections ||= self.class._reflections.deep_dup).each do |key, reflection|
      next if reflection.excluded?(self)
      next unless include_directive.key?(key)

      association = reflection.build_association(self, instance_options, include_slice)
      y.yield association
    end
  end
end

#associations_hash(adapter_options, options, adapter_instance) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



414
415
416
417
418
419
420
421
# File 'lib/active_model/serializer.rb', line 414

def associations_hash(adapter_options, options, adapter_instance)
  include_directive = options.fetch(:include_directive)
  include_slice = options[:include_slice]
  associations(include_directive, include_slice).each_with_object({}) do |association, relationships|
    adapter_opts = adapter_options.merge(include_directive: include_directive[association.key], adapter_instance: adapter_instance)
    relationships[association.key] = association.serializable_hash(adapter_opts, adapter_instance)
  end
end

#attributes(requested_attrs = nil, reload = false) ⇒ Object

Return the attributes of object as presented by the serializer.



336
337
338
339
340
341
342
343
# File 'lib/active_model/serializer.rb', line 336

def attributes(requested_attrs = nil, reload = false)
  @attributes = nil if reload
  @attributes ||= self.class._attributes_data.each_with_object({}) do |(key, attr), hash|
    next if attr.excluded?(self)
    next unless requested_attrs.nil? || requested_attrs.include?(key)
    hash[key] = attr.value(self)
  end
end

#attributes_hash(_adapter_options, options, adapter_instance) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



403
404
405
406
407
408
409
410
411
# File 'lib/active_model/serializer.rb', line 403

def attributes_hash(_adapter_options, options, adapter_instance)
  if self.class.cache_enabled?
    fetch_attributes(options[:fields], options[:cached_attributes] || {}, adapter_instance)
  elsif self.class.fragment_cache_enabled?
    fetch_attributes_fragment(adapter_instance, options[:cached_attributes] || {})
  else
    attributes(options[:fields], true)
  end
end

#json_keyObject

Used by adapter as resource root.



385
386
387
388
389
390
391
392
# File 'lib/active_model/serializer.rb', line 385

def json_key
  root || _type ||
    begin
      object.class.model_name.to_s.underscore
    rescue ArgumentError
      'anonymous_object'
    end
end

#read_attribute_for_serialization(attr) ⇒ Object



394
395
396
397
398
399
400
# File 'lib/active_model/serializer.rb', line 394

def read_attribute_for_serialization(attr)
  if respond_to?(attr)
    send(attr)
  else
    object.read_attribute_for_serialization(attr)
  end
end

#serializable_hash(adapter_options = nil, options = {}, adapter_instance = self.class.serialization_adapter_instance) ⇒ Hash Also known as: to_hash, to_h

associations, similar to how ActiveModel::Serializers::JSON is used in ActiveRecord::Base.

Returns:

  • (Hash)

    containing the attributes and first level



366
367
368
369
370
371
372
373
374
375
# File 'lib/active_model/serializer.rb', line 366

def serializable_hash(adapter_options = nil, options = {}, adapter_instance = self.class.serialization_adapter_instance)
  adapter_options ||= {}
  options[:include_directive] ||= ActiveModel::Serializer.include_directive_from_options(adapter_options)
  if (fieldset = adapter_options[:fieldset])
    options[:fields] = fieldset.fields_for(json_key)
  end
  resource = attributes_hash(adapter_options, options, adapter_instance)
  relationships = associations_hash(adapter_options, options, adapter_instance)
  resource.merge(relationships)
end

#success?Boolean

Returns:

  • (Boolean)


330
331
332
# File 'lib/active_model/serializer.rb', line 330

def success?
  true
end