123456789_123456789_123456789_123456789_123456789_

Module: ActiveModel::Serialization

Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Included In:
Defined in: activemodel/lib/active_model/serialization.rb

Overview

Provides a basic serialization to a serializable_hash for your objects.

A minimal implementation could be:

class Person
  include ActiveModel::Serialization

  attr_accessor :name

  def attributes
    {'name' => nil}
  end
end

Which would provide you with:

person = Person.new
person.serializable_hash   # => {"name"=>nil}
person.name = "Bob"
person.serializable_hash   # => {"name"=>"Bob"}

An attributes hash must be defined and should contain any attributes you need to be serialized. Attributes must be strings, not symbols. When called, serializable hash will use instance methods that match the name of the attributes hash’s keys. In order to override this behavior, take a look at the private method #read_attribute_for_serialization.

Serializers::JSON module automatically includes the Serialization module, so there is no need to explicitly include Serialization.

A minimal implementation including JSON would be:

class Person
  include ActiveModel::Serializers::JSON

  attr_accessor :name

  def attributes
    {'name' => nil}
  end
end

Which would provide you with:

person = Person.new
person.serializable_hash   # => {"name"=>nil}
person.as_json             # => {"name"=>nil}
person.to_json             # => "{\"name\":null}"

person.name = "Bob"
person.serializable_hash   # => {"name"=>"Bob"}
person.as_json             # => {"name"=>"Bob"}
person.to_json             # => "{\"name\":\"Bob\"}"

Valid options are :only, :except, :methods and :include. The following are all valid examples:

person.serializable_hash(only: 'name')
person.serializable_hash(include: :address)
person.serializable_hash(include: { address: { only: 'city' }})

Instance Method Summary

Instance Method Details

#attribute_names_for_serialization (private)

[ GitHub ]

  
# File 'activemodel/lib/active_model/serialization.rb', line 152

def attribute_names_for_serialization
  attributes.keys
end

#read_attribute_for_serialization (private)

Hook method defining how an attribute value should be retrieved for serialization. By default this is assumed to be an instance named after the attribute. Override this method in subclasses should you need to retrieve the value for a given attribute differently:

class MyClass
  include ActiveModel::Serialization

  def initialize(data = {})
    @data = data
  end

  def read_attribute_for_serialization(key)
    @data[key]
  end
end
[ GitHub ]

  
# File 'activemodel/lib/active_model/serialization.rb', line 172

alias :read_attribute_for_serialization :send

#serializable_add_includes(options = {}) (private)

This method is for internal use only.

Add associations specified via the :include option.

Expects a block that takes as arguments:

association - name of the association
records     - the association record(s) to be serialized
opts        - options for the association records
[ GitHub ]

  
# File 'activemodel/lib/active_model/serialization.rb', line 184

def serializable_add_includes(options = {}) # :nodoc:
  return unless includes = options[:include]

  unless includes.is_a?(Hash)
    includes = Hash[Array(includes).flat_map { |n| n.is_a?(Hash) ? n.to_a : [[n, {}]] }]
  end

  includes.each do |association, opts|
    if records = send(association)
      yield association, records, opts
    end
  end
end

#serializable_attributes(attribute_names) (private)

[ GitHub ]

  
# File 'activemodel/lib/active_model/serialization.rb', line 174

def serializable_attributes(attribute_names)
  attribute_names.index_with { |n| read_attribute_for_serialization(n) }
end

#serializable_hash(options = nil)

Returns a serialized hash of your object.

class Person
  include ActiveModel::Serialization

  attr_accessor :name, :age

  def attributes
    {'name' => nil, 'age' => nil}
  end

  def capitalized_name
    name.capitalize
  end
end

person = Person.new
person.name = 'bob'
person.age  = 22
person.serializable_hash                # => {"name"=>"bob", "age"=>22}
person.serializable_hash(only: :name)   # => {"name"=>"bob"}
person.serializable_hash(except: :name) # => {"age"=>22}
person.serializable_hash(methods: :capitalized_name)
# => {"name"=>"bob", "age"=>22, "capitalized_name"=>"Bob"}

Example with :include option

class User
  include ActiveModel::Serializers::JSON
  attr_accessor :name, :notes # Emulate has_many :notes
  def attributes
    {'name' => nil}
  end
end

class Note
  include ActiveModel::Serializers::JSON
  attr_accessor :title, :text
  def attributes
    {'title' => nil, 'text' => nil}
  end
end

note = Note.new
note.title = 'Battle of Austerlitz'
note.text = 'Some text here'

user = User.new
user.name = 'Napoleon'
user.notes = [note]

user.serializable_hash
# => {"name" => "Napoleon"}
user.serializable_hash(include: { notes: { only: 'title' }})
# => {"name" => "Napoleon", "notes" => [{"title"=>"Battle of Austerlitz"}]}
[ GitHub ]

  
# File 'activemodel/lib/active_model/serialization.rb', line 125

def serializable_hash(options = nil)
  attribute_names = attribute_names_for_serialization

  return serializable_attributes(attribute_names) if options.blank?

  if only = options[:only]
    attribute_names &= Array(only).map(&:to_s)
  elsif except = options[:except]
    attribute_names -= Array(except).map(&:to_s)
  end

  hash = serializable_attributes(attribute_names)

  Array(options[:methods]).each { |m| hash[m.to_s] = send(m) }

  serializable_add_includes(options) do |association, records, opts|
    hash[association.to_s] = if records.respond_to?(:to_ary)
      records.to_ary.map { |a| a.serializable_hash(opts) }
    else
      records.serializable_hash(opts)
    end
  end

  hash
end