Class: ActiveModel::Serializer

Inherits:
Object
  • Object
show all
Defined in:
lib/active_model/serializer.rb

Overview

Active Model Serializer

Provides a basic serializer implementation that allows you to easily control how a given object is going to be serialized. On initialization, it expects to object as arguments, a resource and a scope. For example, one may do in a controller:

PostSerializer.new(@post, current_user).to_json

The object to be serialized is the @post and the scope is current_user.

We use the scope to check if a given attribute should be serialized or not. For example, some attributes maybe only be returned if current_user is the author of the post:

class PostSerializer < ActiveModel::Serializer
  attributes :title, :body
  has_many :comments

  private

  def attributes
    hash = super
    hash.merge!(:email => post.email) if author?
    hash
  end

  def author?
    post.author == scope
  end
end

Defined Under Namespace

Modules: Associations

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(object, scope, options = {}) ⇒ Serializer

Returns a new instance of Serializer.



265
266
267
268
# File 'lib/active_model/serializer.rb', line 265

def initialize(object, scope, options={})
  @object, @scope, @options = object, scope, options
  @hash = options[:hash]
end

Instance Attribute Details

#objectObject (readonly)

Returns the value of attribute object.



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

def object
  @object
end

#scopeObject (readonly)

Returns the value of attribute scope.



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

def scope
  @scope
end

Class Method Details

.associate(klass, attrs) ⇒ Object

:nodoc:



151
152
153
154
155
156
157
158
159
# File 'lib/active_model/serializer.rb', line 151

def associate(klass, attrs) #:nodoc:
  options = attrs.extract_options!
  self._associations += attrs.map do |attr|
    unless method_defined?(attr)
      class_eval "def #{attr}() object.#{attr} end", __FILE__, __LINE__
    end
    klass.new(attr, options)
  end
end

.attribute(attr, options = {}) ⇒ Object



147
148
149
# File 'lib/active_model/serializer.rb', line 147

def attribute(attr, options={})
  self._attributes = _attributes.merge(attr => options[:key] || attr)
end

.attributes(*attrs) ⇒ Object

Define attributes to be used in the serialization.



139
140
141
142
143
144
145
# File 'lib/active_model/serializer.rb', line 139

def attributes(*attrs)
  self._attributes = _attributes.dup

  attrs.each do |attr|
    self._attributes[attr] = attr
  end
end

.embed(type, options = {}) ⇒ Object

Define how associations should be embedded.

embed :objects               # Embed associations as full objects
embed :ids                   # Embed only the association ids
embed :ids, :include => true # Embed the association ids and include objects in the root


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

def embed(type, options={})
  self._embed = type
  self._root_embed = true if options[:include]
end

.has_many(*attrs) ⇒ Object

Defines an association in the object should be rendered.

The serializer object should implement the association name as a method which should return an array when invoked. If a method with the association name does not exist, the association name is dispatched to the serialized object.



167
168
169
# File 'lib/active_model/serializer.rb', line 167

def has_many(*attrs)
  associate(Associations::HasMany, attrs)
end

.has_one(*attrs) ⇒ Object

Defines an association in the object should be rendered.

The serializer object should implement the association name as a method which should return an object when invoked. If a method with the association name does not exist, the association name is dispatched to the serialized object.



177
178
179
# File 'lib/active_model/serializer.rb', line 177

def has_one(*attrs)
  associate(Associations::HasOne, attrs)
end

.inherited(klass) ⇒ Object

:nodoc:



252
253
254
255
256
257
258
259
260
# File 'lib/active_model/serializer.rb', line 252

def inherited(klass) #:nodoc:
  return if klass.anonymous?
  name = klass.name.demodulize.underscore.sub(/_serializer$/, '')

  klass.class_eval do
    alias_method name.to_sym, :object
    root name.to_sym unless self._root == false
  end
end

.model_classObject

The model class associated with this serializer.



232
233
234
# File 'lib/active_model/serializer.rb', line 232

def model_class
  name.sub(/Serializer$/, '').constantize
end

.root(name) ⇒ Object

Defines the root used on serialization. If false, disables the root.



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

def root(name)
  self._root = name
end

.schemaObject

Return a schema hash for the current serializer. This information can be used to generate clients for the serialized output.

The schema hash has two keys: attributes and associations.

The attributes hash looks like this:

{ :name => :string, :age => :integer }

The associations hash looks like this:

{ :posts => { :has_many => :posts } }

If :key is used:

class PostsSerializer < ActiveModel::Serializer
  has_many :posts, :key => :my_posts
end

the hash looks like this:

{ :my_posts => { :has_many => :posts }

This information is extracted from the serializer’s model class, which is provided by SerializerClass.model_class.

The schema method uses the columns_hash and reflect_on_association methods, provided by default by ActiveRecord. You can implement these methods on your custom models if you want the serializer’s schema method to work.

TODO: This is currently coupled to Active Record. We need to figure out a way to decouple those two.



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/active_model/serializer.rb', line 214

def schema
  klass = model_class
  columns = klass.columns_hash

  attrs = _attributes.inject({}) do |hash, (name,key)|
    column = columns[name.to_s]
    hash.merge key => column.type
  end

  associations = _associations.inject({}) do |hash, association|
    model_association = klass.reflect_on_association(association.name)
    hash.merge association.key => { model_association.macro => model_association.name }
  end

  { :attributes => attrs, :associations => associations }
end

Instance Method Details

#as_json(options = nil) ⇒ Object

Returns a json representation of the serializable object including the root.



272
273
274
275
276
277
278
279
280
281
# File 'lib/active_model/serializer.rb', line 272

def as_json(options=nil)
  options ||= {}
  if root = options.fetch(:root, @options.fetch(:root, _root))
    @hash = hash = {}
    hash.merge!(root => serializable_hash)
    hash
  else
    @hash = serializable_hash
  end
end

#association_idsObject

Returns a hash representation of the serializable object associations ids.



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

def association_ids
  hash = {}

  _associations.each do |association|
    associated_object = send(association.name)
    hash.merge! association.serialize_ids(associated_object, scope)
  end

  hash
end

#associationsObject

Returns a hash representation of the serializable object associations.



310
311
312
313
314
315
316
317
318
319
# File 'lib/active_model/serializer.rb', line 310

def associations
  hash = {}

  _associations.each do |association|
    associated_object = send(association.name)
    hash.merge! association.serialize(associated_object, scope, self, :hash => @hash)
  end

  hash
end

#attributesObject

Returns a hash representation of the serializable object attributes.



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

def attributes
  hash = {}

  _attributes.each do |name,key|
    hash[key] = @object.read_attribute_for_serialization(name)
  end

  hash
end

#merge_associations(hash, associations) ⇒ Object

Merge associations for embed case by always adding root associations to the given hash.



298
299
300
301
302
303
304
305
306
# File 'lib/active_model/serializer.rb', line 298

def merge_associations(hash, associations)
  associations.each do |key, value|
    if hash[key]
      hash[key] |= value
    elsif value
      hash[key] = value
    end
  end
end

#serializable_hashObject

Returns a hash representation of the serializable object without the root.



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

def serializable_hash
  if _embed == :ids
    merge_associations(@hash, associations) if _root_embed
    attributes.merge(association_ids)
  elsif _embed == :objects
    attributes.merge(associations)
  else
    attributes
  end
end