We are developing a backend with pure JSON communication in Rails and use Devise for user authentication. Unfortunately, the password reset functions don't seem to support JSON at all. I've tried to implement the following in a custom controller.
def create
@user = User.send_reset_password_instructions(params[:user])
if successfully_sent?(@user)
head :status => 200
else
render :status => 422, :json => { :errors => @user.errors.full_messages }
end
end
Route used for this:
scope '/api/v1' do
devise_for :users, :skip => :sessions, :controllers => { :passwords => 'api/v1/users/passwords' }
end
The successfully_sent method was copy&pasted from the DeviseController but still, instead of printing just status 200, it renders devise/mailer/reset_password_instructions.html.erb which confuses the JSON client.
Is there any way to make the password workflow support JSON?
The default Devise controller is supposed to work just fine, you just need to call in your ApplicationController (or in your DeviseController child) respond_to :json to tell it should also return json responses.
You are right, thank you. Maybe I was confused what it needs new_user_session_path for. I don't use sessions so I skipped the session routes in devise_for. Does resetting work only with sessions enabled or is there some trick?
I would consider the fact it needs new_user_session_path for APIs a bug. :) Could you provide a fix + test case?
The issue happens because the same URL we use to redirect for HTML is also being used for JSON:
We should probably check if it is a navigational format or not and return something different. This also happens in other controllers. :S
You mean something like...
def after_sending_reset_password_instructions_path_for(resource_name)
if is_navigational_format?
new_session_path(resource_name)
else
# Do nothing?
end
end
Or even..
def after_sending_reset_password_instructions_path_for(resource_name)
new_session_path(resource_name) if is_navigational_format?
end
Don't know if that's even valid. Just trying to contribute to this great gem here. ;-)
I think that would be fine, yeah. As long as we are not returning a 201 nor a redirect, we don't need to add the Location header.
If it is not asking too much, would you mind sending pull requests for fixing this issue in the other controllers too? Confirmations and unlocks controller have the same issue. Thank you!
Sure thing. Hope I'll do this right. First contribution to an open-source project, I'm excited.
https://github.com/plataformatec/devise/pull/2407
I hope, this does the trick. Unfortunately, I don't know how to test this, but in theory, it should cover the relevant API functions.
Just checked: PUT /resource/password works fine without any changes with JSON only. If the password reset works, it just returns 204 No Content
edit: Right, we are trying to solve the dependency on session_path. That it works with sessions enabled is not surprising, nevermind.
Congratulations on your first contribution!
Glad I could help!
Most helpful comment
Congratulations on your first contribution!