class ActiveModel::Serializer::Reflection

Holds all the meta-data about an association as it was specified in the ActiveModel::Serializer class.

@example

 class PostSerializer < ActiveModel::Serializer
   has_one :author, serializer: AuthorSerializer
   belongs_to :boss, type: :users, foreign_key: :boss_id
   has_many :comments
   has_many :comments, key: :last_comments do
     object.comments.last(1)
   end
   has_many :secret_meta_data, if: :is_admin?

   has_one :blog do |serializer|
     meta count: object.roles.count
     serializer.cached_blog
   end

   private

   def cached_blog
     cache_store.fetch("cached_blog:#{object.updated_at}") do
       Blog.find(object.blog_id)
     end
   end

   def is_admin?
     current_user.admin?
   end
 end

Specifically, the association 'comments' is evaluated two different ways:
1) as 'comments' and named 'comments'.
2) as 'object.comments.last(1)' and named 'last_comments'.

PostSerializer._reflections # =>
  # {
  #   author: HasOneReflection.new(:author, serializer: AuthorSerializer),
  #   comments: HasManyReflection.new(:comments)
  #   last_comments: HasManyReflection.new(:comments, { key: :last_comments }, #<Block>)
  #   secret_meta_data: HasManyReflection.new(:secret_meta_data, { if: :is_admin? })
  # }

So you can inspect reflections in your Adapters.

Attributes

foreign_key[R]
object[RW]

used in instance exec

scope[RW]

used in instance exec

type[R]

Public Class Methods

new(*) click to toggle source
Calls superclass method
# File lib/active_model/serializer/reflection.rb, line 55
def initialize(*)
  super
  options[:links] = {}
  options[:include_data_setting] = Serializer.config.include_data_default
  options[:meta] = nil
  @type = options.fetch(:type) do
    class_name = options.fetch(:class_name, name.to_s.camelize.singularize)
    class_name.underscore.pluralize.to_sym
  end
  @foreign_key = options.fetch(:foreign_key) do
    if collection?
      "#{name.to_s.singularize}_ids".to_sym
    else
      "#{name}_id".to_sym
    end
  end
end

Public Instance Methods

build_association(parent_serializer, parent_serializer_options, include_slice = {}) click to toggle source

Build association. This method is used internally to build serializer's association by its reflection.

@param [Serializer] parent_serializer for given association @param [Hash{Symbol => Object}] parent_serializer_options

@example

# Given the following serializer defined:
class PostSerializer < ActiveModel::Serializer
  has_many :comments, serializer: CommentSummarySerializer
end

# Then you instantiate your serializer
post_serializer = PostSerializer.new(post, foo: 'bar') #
# to build association for comments you need to get reflection
comments_reflection = PostSerializer._reflections.detect { |r| r.name == :comments }
# and #build_association
comments_reflection.build_association(post_serializer, foo: 'bar')

@api private

# File lib/active_model/serializer/reflection.rb, line 197
def build_association(parent_serializer, parent_serializer_options, include_slice = {})
  association_options = {
    parent_serializer: parent_serializer,
    parent_serializer_options: parent_serializer_options,
    include_slice: include_slice
  }
  Association.new(self, association_options)
end
collection?() click to toggle source
# File lib/active_model/serializer/reflection.rb, line 138
def collection?
  false
end
foreign_key_on() click to toggle source

@api private

# File lib/active_model/serializer/reflection.rb, line 173
def foreign_key_on
  :related
end
include_data(value = true) click to toggle source

@api public @example

has_one :blog do
  include_data false
  link :self, 'a link'
  link :related, 'another link'
end

has_one :blog do
  include_data false
  link :self, 'a link'
  link :related, 'another link'
end

 belongs_to :reviewer do
   meta name: 'Dan Brown'
   include_data true
 end

 has_many :tags, serializer: TagSerializer do
   link :self, '//example.com/link_author/relationships/tags'
   include_data :if_sideloaded
 end
# File lib/active_model/serializer/reflection.rb, line 133
def include_data(value = true)
  options[:include_data_setting] = value
  :nil
end
include_data?(include_slice) click to toggle source
# File lib/active_model/serializer/reflection.rb, line 142
def include_data?(include_slice)
  include_data_setting = options[:include_data_setting]
  case include_data_setting
  when :if_sideloaded then include_slice.key?(options.fetch(:key, name))
  when true           then true
  when false          then false
  else fail ArgumentError, "Unknown include_data_setting '#{include_data_setting.inspect}'"
  end
end
meta(value = nil) click to toggle source

@api public @example

has_one :blog do
  include_data false
  meta(id: object.blog.id)
  meta liked: object.likes.any?
  link :self do
    href object.blog.id.to_s
    meta(id: object.blog.id)
  end
# File lib/active_model/serializer/reflection.rb, line 105
def meta(value = nil)
  options[:meta] = block_given? ? Proc.new : value
  :nil
end
value(serializer, include_slice) click to toggle source

@param serializer [ActiveModel::Serializer] @yield [ActiveModel::Serializer] @return [:nil, associated resource or resource collection]

# File lib/active_model/serializer/reflection.rb, line 155
def value(serializer, include_slice)
  # NOTE(BF): This method isn't thread-safe because the _reflections class attribute is not thread-safe
  # Therefore, when we build associations from reflections, we dup the entire reflection instance.
  # Better solutions much appreciated!
  @object = serializer.object
  @scope = serializer.scope

  block_value = instance_exec(serializer, &block) if block
  return unless include_data?(include_slice)

  if block && block_value != :nil
    block_value
  else
    serializer.read_attribute_for_serialization(name)
  end
end