'Active Model Serializer - How do I include an attribute conditionally? Rails
I am using Active Model Serializers with my Rails 4 API, and I have been trying to figure out how to include the auth_token attribute in my JSON response only when the user logs in at sessions#create. I read the AMS documentation and tried most of the seeming solutions but none worked.
Couple things to point out:
:auth_tokenis not in theUserSerializer's attributes list.- Since the
auth_tokenis controller-specific, I can't do the conditional logic in theUserSerializerunless there is a way to determine what controller was called in the Serializer. So nodef include_auth_token? ... end.
Some of the things I've tried already:
class Api::V1::SessionsController < ApplicationController
if user = User.authenticate(params[:session][:email], params[:session][:password])
if user.active
user.generate_auth_token #=> Custom method
user.save
# Tried using the meta param
render :json => user, :meta => {:auth_token => user.auth_token}
# Tried using the include param both with 'auth_token' and 'user.auth_token'
render :json => user, include: 'user.auth_token'
end
end
end
Ideally, I would like to be able to use something along the lines of render :json => user, :include => :auth_token to additionally include attributes not already defined in the UserSerializer.
What is the proper way to conditionally include attributes from the controller with AMS?
Solution 1:[1]
After reading the documentation, looks like the include will be available only in the v0.10.0 version. The correct docs from v0.9 are these: https://github.com/rails-api/active_model_serializers/tree/v0.9.0#attributes.
I've used the filter method before, something like this should do the trick:
class Api::V1::SessionsController < ApplicationController
if user = User.authenticate(params[:session][:email], params[:session][:password])
if user.active
user.generate_auth_token
user.save
render :json => user, :meta => {:auth_token => user.auth_token}
end
end
end
class UserSerializer < ActiveModel::Serializer
attributes :id, :name, :auth_token
def filter(keys)
if meta && meta['auth_token']
keys
else
keys - [:auth_token]
end
end
end
Solution 2:[2]
Instead of relying on the render :json => user call to serialize the user to a JSON payload, you can craft the payload yourself and have control over what is and what is not included.
user_payload = user.as_json
user_payload.merge!(:auth_token => user.auth_token) if include_auth_token?
render :json => user_payload
The as_json method Returns a hash representing the model. You can then modify this hash before the JSON serializer turns it into proper JSON.
Solution 3:[3]
You can define attributes conditionally. See here.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | tegon |
| Solution 2 | yez |
| Solution 3 | Van_Paitin |
