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.90'.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.



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

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



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

def object
  @object
end

#rootObject

END SERIALIZER MACROS



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

def root
  @root
end

#scopeObject

END SERIALIZER MACROS



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

def scope
  @scope
end

Class Method Details

._attributesArray<Symbol>

Returns Key names of declared attributes.

See Also:

  • Serializer::attribute

Returns:

  • Key names of declared attributes



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

def self._attributes
  _attributes_data.keys
end

.adapterObject

Deprecated



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

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


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

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


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

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:

  • of the association

  • (defaults to: {})

    for the reflection



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

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

API:

  • private



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

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)
    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:

  • of the association

  • (defaults to: {})

    for the reflection



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

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:

  • of the association

  • (defaults to: {})

    for the reflection



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

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.

API:

  • private



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

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



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

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" }


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

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


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

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.

API:

  • private



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

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:

  • Preferentially returns

    1. resource.serializer_class

    2. ArraySerializer when resource is a collection

    3. options

    4. lookup serializer when resource is a Class



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

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.

API:

  • private



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

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.



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

def self.serializers_cache
  @serializers_cache ||= ThreadSafe::Cache.new
end

.type(type) ⇒ Object

Set the JSON API type of a serializer.

Examples:

class AdminAuthorSerializer < ActiveModel::Serializer
  type 'authors'


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

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

Instance Method Details

#as_json(adapter_opts = nil) ⇒ Object

See Also:



376
377
378
# File 'lib/active_model/serializer.rb', line 376

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

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

Parameters:

  • (defaults to: ActiveModelSerializers.default_include_directive)

    (defaults to the default_include_directive config value when not provided)

Returns:



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

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.

API:

  • private



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

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.



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

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.

API:

  • private



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

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.



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

def json_key
  root || _type || object.class.model_name.to_s.underscore
end

#read_attribute_for_serialization(attr) ⇒ Object



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

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:

  • containing the attributes and first level



365
366
367
368
369
370
371
# File 'lib/active_model/serializer.rb', line 365

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)
  resource = attributes_hash(adapter_options, options, adapter_instance)
  relationships = associations_hash(adapter_options, options, adapter_instance)
  resource.merge(relationships)
end

#success?Boolean

Returns:



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

def success?
  true
end