Conditional attributes in Active Model Serializers
How do I render an attribute only if some condition is true?
For example, I want to render User's token attribute on create action.
Solution 1:
In the latest version (0.10.x
), you can also do it this way:
class EntitySerializer < ActiveModel::Serializer
attributes :id, :created_at, :updated_at
attribute :conditional_attr, if: :condition?
def condition?
#condition code goes here
end
end
For example:
class UserSerializer < ActiveModel::Serializer
attributes :id, :username, :name, :email, :created_at, :updated_at
attribute :auth_token, if: :auth_token?
def created_at
object.created_at.to_i
end
def updated_at
object.updated_at.to_i
end
def auth_token?
true if object.auth_token
end
end
EDIT (Suggested by Joe Essey) :
This method does not work with latest version (0.10
)
With the version 0.8
it is even simpler. You don't have to use the if: :condition?
. Instead you can use the following convention to achieve the same result.
class EntitySerializer < ActiveModel::Serializer
attributes :id, :created_at, :updated_at
attribute :conditional_attr
def include_conditional_attr?
#condition code goes here
end
end
The example above would look like this.
class UserSerializer < ActiveModel::Serializer
attributes :id, :username, :name, :email, :created_at, :updated_at
attribute :auth_token
def created_at
object.created_at.to_i
end
def updated_at
object.updated_at.to_i
end
def include_auth_token?
true if object.auth_token
end
end
See 0.8 documentation for more details.
Solution 2:
you can override the attributes
method, here is a simple example:
class Foo < ActiveModel::Serializer
attributes :id
def attributes(*args)
hash = super
hash[:last_name] = 'Bob' unless object.persisted?
hash
end
end
Solution 3:
You could start by setting a condition on the serializers 'initialize' method. This condition can be passed from wherever else in your code, included in the options hash that 'initialize' accepts as second argument:
class SomeCustomSerializer < ActiveModel::Serializer
attributes :id, :attr1, :conditional_attr2, :conditional_attr2
def initialize(object, options={})
@condition = options[:condition].present? && options[:condition]
super(object, options)
end
def attributes(*args)
return super unless @condition #get all the attributes
attributes_to_remove = [:conditional_attr2, :conditional_attr2]
filtered = super.except(*attributes_to_remove)
filtered
end
end
In this case attr1 would always be passed, while the conditional attributes would be hidden if the condition is true.
You would get the result of this custom serialization wherever else in your code as follows:
custom_serialized_object = SomeCustomSerializer.new(object_to_serialize, {:condition => true})
I hope this was useful!