josevalim/active_model_serializers — pull request #47 by dgeb (2012-04-08 02:42:14+00:00)
Title: introduced :if, :unless, and :value options to attribute

I'd like to introduce `:if`, `:unless` and `:value` options to `attribute`. These options will enable the following capabilities, as described in the changes to the README:

***

Use an `:if` or `:unless` option to conditionally include a particular attribute:

class PostSerializer < ApplicationSerializer
attributes :id, :body
attribute :admin_note, :if => :admin? # will be evaluated by the serializer (see below)
attribute :hidden, :if => :hidden? # will be evaluated on the serialized object
attribute :synopsis, :unless => lambda { |serializer| serializer.object.content.size < 100 }

has_many :comments

def admin?
scope.admin?
end
end

Use the `:value` option to define a value other than the attribute on the serialized object:

class UserSerializer < ApplicationSerializer
attribute :first_name
attribute :last_name, :value => lambda { |serializer| serializer.object.last_name.upcase }
attribute :full_name, :value => :full_name # will be evaluated by the serializer (see below)
attribute :code_name, :value => :code # will be evaluated on the serialized object
attribute :admin, :value => true, :if => :show_admin? # value is static

def full_name do
"#{object.first_name} #{object.last_name}"
end

def show_admin?
scope.admin? && object.admin?
end
end

The `:value` option can optionally be combined with `:if` or `:unless`.

All of these options can be either procs (see the `lambda` examples above), methods on the serializer, methods on the serialized object, or simply static values. Arguments are evaluated in that order.

***

This is similar to #36, and is somewhat based off @wycats' suggestion to use a `:value` option instead of a block. However, it differs from that suggestion because it keeps the attribute definition at the class (not instance) level, which I think is important for consistency and ordering purposes.