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

Returns:

  • (Array<Symbol>)

    Key names of declared attributes

See Also:

  • Serializer::attribute


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:

  • name (Symbol)

    of the association

  • options (Hash<Symbol => any>) (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


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, 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



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:

  • name (Symbol)

    of the association

  • options (Hash<Symbol => any>) (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.



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.



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:

  • (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



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.



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:



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

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:



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.



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

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.



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

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.



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

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



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

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



365
366
367
368
369
370
371
372
373
374
# 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)
  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)


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

def success?
  true
end