I'm working on a JSON-based API for my Rails 3.1 app. I'd like to provide a custom failure response instead of the default, which is:
{"error":"You need to sign in or sign up before continuing."}
My API controller includes a before_filter call to authenticate_user!
, which is what is rendering this JSON response.
While searching, I came across this StackOverflow question, which references this Devise wiki entry. Unfortunately, the wiki entry isn't verbose enough for me to understand what it's telling me. Specifically, I have no clue where I'm supposed to put that code such that Devise/Warden knows to render what I want returned.
From the comments on the other SA question, it sounds like I don't need to call custom_failure!
since I'm using a version of Devise above 1.2 (1.4.2 to be specific). However, the wiki entry doesn't explain where the render
call should go such that authenticate_user!
knows to use that instead of its own render call.
Where does this render
call go?
Edit: I'm not just trying to change the message itself (a la the devise en.yml
config); I'm trying to change the actual format of the response. Specifically, I want to return this:
render :text => "You must be logged in to do that.", :status => :unauthorized
For reference in case anyone else stumbles upon this question when looking for how to customize the json error response when a failed login attempt is made using Devise, the key is to use your own custom FailureApp
implementation. (You can also use this approach to override some redirect behavior.)
class CustomFailureApp < Devise::FailureApp
def respond
if request.format == :json
json_error_response
else
super
end
end
def json_error_response
self.status = 401
self.content_type = "application/json"
self.response_body = [ { message: i18n_message } ].to_json
end
end
and in your devise.rb
, look for the config.warden
section:
config.warden do |manager|
manager.failure_app = CustomFailureApp
end
Some related info:
At first I thought I would have to override Devise::SessionsController, possibly using the recall
option passed to warden.authenticate!
, but as mentioned here, "recall is not invoked for API requests, only for navigational ones. If you want to customise the http status code, you will have better luck doing so at the failure app level."
Also https://github.com/plataformatec/devise/wiki/How-To%3a-Redirect-to-a-specific-page-when-the-user-can-not-be-authenticated shows something very similar for redirection.