joseph.hainline
joseph.hainline

Reputation: 26658

Customize Devise user JSON response on creation of a user account

How do I customize the JSON output on creation of a devise User?

### User.rb ###
class User < ActiveRecord::Base
  devise :database_authenticatable,
         :registerable, ...
  ...
end

### Routes.rb ###
...
devise_for :users, :controllers => {:registrations => "registrations"}
...

I've got some extra fields in my User table that are secret, but they get returned in the JSON response when I do a User creation via JSON like this:

$ curl -H "Content-Type: application/json" -d '{"user" : {"username":"someone","email":"[email protected]","password":"awesomepass"}}' -X POST http://localhost:3000/users.json

which returns:

{"user":{"secret_field_1":"some value","secret_field_2":"some value","created_at":"2013-07-25T21:24:50-05:00","email":"[email protected]","first_name":null,"id":3226,"last_name":null,"updated_at":"2013-07-25T21:24:50-05:00","username":"someone"}}

I'd like to hide those secret fields, but don't know how to customize the JSON response.

I've tried a standard ActiveRecord serializer:

class UserSerializer < ActiveModel::Serializer
  attributes :id, :created_at, :updated_at, :email, :first_name, :last_name, :username
end

to no avail, I'm guessing because of Devise.

Upvotes: 8

Views: 7628

Answers (5)

Grace Han
Grace Han

Reputation: 26

I just had the same problem, below is how I resolved it, very simple.

All these passed in active_model_serializers (0.9.5)

Override Devise registration method, and in your customize action:

def registration
  //Some process, and you get a @user when registration is successful.

  render :json => UserSerializer.new(@user)
end

If you want to pass some parameters to your customized Serializer(token for example), you can pass it in your action:

render :json => UserSerializer.new(@user).as_json({auth_token: your_token})

And in your serializer, just use:

class UserSerializer < ActiveModel::Serializer
  attributes :id, :name, :avatar_url, :auth_token

  def auth_token
    serialization_options[:auth_token]
  end
end

Upvotes: 0

Gowiem
Gowiem

Reputation: 1408

I recently ran into this and overriding respond_with didn't fix the issue. I ended up overriding to_json in user.rb like so:

def to_json(arg)
  UserSerializer.new(self).to_json
end

Not sure what the extra arg is, but that seems to be required by one of the devise mixins.

I'm using the following:

  • Rails 4.2.0
  • Devise 3.4.1

Upvotes: 3

iainbeeston
iainbeeston

Reputation: 1911

Just a guess, but it sounds like rails is not finding your serializer and is using to_json(). Did you define active_model_serializer() in your model?

Upvotes: 0

mattwindwer
mattwindwer

Reputation: 929

I just ran into the same issue. I haven't pinpointed exactly why but it looks like respond_with in Devise's SessionsController (tested on Devise 3.0 and active_model_serializers 0.8.1) doesn't trigger the ActiveModel::Serializer.

So I overrode respond_with in my controller:

class SessionsController < Devise::SessionsController

  def respond_with(resource, opts = {})
    render json: resource # Triggers the appropriate serializer
  end

end

It is, however, working in my RegistrationsController with respond_with. There I needed to do the following:

class RegistrationsController < Devise::RegistrationsController

  respond_to :json
end

Upvotes: 12

Jeremy
Jeremy

Reputation: 167

Depending on what you are doing with that JSON, you simply have to remove attributes you don't want from your serializer.

For example :

class UserSerializer < ActiveModel::Serializer
  attributes :id, :email, :username
end

I presume that, in your case, you just want to do that.

But you also have the possibility to include an attribute on a specific condition :

class PostSerializer < ActiveModel::Serializer
  attributes :id, :title, :body, :author

  def include_author?
    current_user.admin?
  end
end

And finally you can override the attributes method to return the hash you need :

class PersonSerializer < ActiveModel::Serializer
  attributes :first_name, :last_name

  def attributes
    hash = super
    if current_user.admin?
      hash["ssn"] = object.ssn
      hash["secret"] = object.mothers_maiden_name
    end
    hash
  end
end

See README of ActiveModel::Serializers for more informations.

Upvotes: -1

Related Questions