Class: ActiveModel::Serializer

Inherits:
Object
  • Object
show all
Extended by:
ActiveModelSerializers::Deprecate, ActiveSupport::Autoload
Includes:
Caching
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.16'.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.



322
323
324
325
326
327
328
329
330
331
# File 'lib/active_model/serializer.rb', line 322

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



317
318
319
# File 'lib/active_model/serializer.rb', line 317

def object
  @object
end

#rootObject

END SERIALIZER MACROS



317
318
319
# File 'lib/active_model/serializer.rb', line 317

def root
  @root
end

#scopeObject

END SERIALIZER MACROS



317
318
319
# File 'lib/active_model/serializer.rb', line 317

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


200
201
202
# File 'lib/active_model/serializer.rb', line 200

def self._attributes
  _attributes_data.keys
end

.adapterObject

Deprecated



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

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


229
230
231
232
# File 'lib/active_model/serializer.rb', line 229

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


209
210
211
212
213
214
215
# File 'lib/active_model/serializer.rb', line 209

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



252
253
254
# File 'lib/active_model/serializer.rb', line 252

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


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

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



241
242
243
# File 'lib/active_model/serializer.rb', line 241

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



263
264
265
# File 'lib/active_model/serializer.rb', line 263

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.



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

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



190
191
192
193
194
195
196
# File 'lib/active_model/serializer.rb', line 190

def self.inherited(base)
  super
  base._attributes_data = _attributes_data.dup
  base._reflections = _reflections.dup
  base._links = _links.dup
  base.config = ActiveSupport::InheritableOptions.new(config)
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" }


288
289
290
291
292
293
# File 'lib/active_model/serializer.rb', line 288

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


303
304
305
# File 'lib/active_model/serializer.rb', line 303

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.



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

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



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

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.



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

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.



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

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'


311
312
313
# File 'lib/active_model/serializer.rb', line 311

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

Instance Method Details

#as_json(adapter_opts = nil) ⇒ Object

See Also:



383
384
385
# File 'lib/active_model/serializer.rb', line 383

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:



351
352
353
354
355
356
357
358
359
360
361
362
363
364
# File 'lib/active_model/serializer.rb', line 351

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.



417
418
419
420
421
422
423
424
# File 'lib/active_model/serializer.rb', line 417

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.



339
340
341
342
343
344
345
346
# File 'lib/active_model/serializer.rb', line 339

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.



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

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.



388
389
390
391
392
393
394
395
# File 'lib/active_model/serializer.rb', line 388

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



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

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



369
370
371
372
373
374
375
376
377
378
# File 'lib/active_model/serializer.rb', line 369

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)


333
334
335
# File 'lib/active_model/serializer.rb', line 333

def success?
  true
end