Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Devise how to change reset_password_token error

I am trying to override Devise's error message 'reset_password_token is invalid' entirely. I would like it to read "password reset link has already been used." How can I do this? There does not seen to be a field or keyword for this in devise.en.yml.

like image 906
Dear1ofGdBear Avatar asked Apr 30 '15 19:04

Dear1ofGdBear


People also ask

Does the reset token from the reset password instructions email match?

Although the reset token from the reset password instructions email matches with the reset token from the database it returns an invalid token error on the changing password form. Database query expose that devise looks for a different token in the database.

Does reset password token is invalid happen all the time?

It doesn't happen all the time. But some time it happens for users that they cannot reset their password as it shows Reset password token is invalid error. I got the same issue with @jimiguru I'm not really sure why the token saved in the db didn't match the reset token being retrieved in the email. can anybody help us with this? thanks!

How do I manually generate a reset password link using devise?

To manually generate a reset password link using devise, the first step is to log in your server and launch the Rails console. Once in there, ask devise for a new reset password token. The call returns two values. The first is the raw token to use in the reset password URL query string, and the second is a hashed version of the token.

What is reset_password_token and how do I use it?

The reset_password_token attribute stores a string token that gets matched with a user and reset_password_sent_at, a datetime attribute that gets compared with Devise’s reset_password_within setting to note when the token should be invalidated. If you don’t have these attributes on the User model, you’ll need to add them before this will work.


Video Answer


2 Answers

A simpler solution than overwriting the passwords_controller, is simply to modify the view:

In app/views/devise/passwords/edit.html.haml (or your erb equivalent), Just put this conditional inside the form:

 - if resource.errors[:reset_password_token].present?
  .alert.alert-danger
    This password reset URL has expired. You may have requested to reset your password more than once. Follow the link in the most recent email or 
    = link_to 'request to reset your password again.', new_user_password_path

And you may want to remove these two lines:

= f.error_notification
= f.full_error :reset_password_token
like image 92
rlarcombe Avatar answered Nov 11 '22 10:11

rlarcombe


Reset password token is invalid message is a validation error thrown while updating password, and is not a devise specific error ( for which the messages stored in devise.en.yml).

This validation happens in the devise/passwords_controller#update method. Code included below:

# PUT /resource/password
def update
  self.resource = resource_class.reset_password_by_token(resource_params)
  yield resource if block_given?

  if resource.errors.empty?
    resource.unlock_access! if unlockable?(resource)
    flash_message = resource.active_for_authentication? ? :updated : :updated_not_active
    set_flash_message(:notice, flash_message) if is_flashing_format?
    sign_in(resource_name, resource)
    respond_with resource, location: after_resetting_password_path_for(resource)
  else
    respond_with resource
  end
end

The self.resource = resource_class.reset_password_by_token(resource_params) line sets the resource.errors object with the error message related to reset_password_token being invalid.

Inspecting the value of resource.errors after this line will show a big hash ending with ... @messages={:reset_password_token=>["is invalid"]}

The devise_error_messages method reformats this to say "Reset Password Token is invalid".

To change this message, the passwords controller should be customized and the update method changed to have a different error message hash.

Steps would be as follows:

1) Customize the routes for passwords controller

# config/routes.rb
devise_for :users, :controllers => { :passwords  => "passwords" }

2) Create the customized passwords controller

# app/controllers/passwords_controller.rb
class PasswordsController < Devise::PasswordsController

end

3) Customize the update method to change the error message:

# app/controllers/passwords_controller.rb 
# Include the update method as it is fully, with the following changes in the else block:

def update
  ...

  if resource.errors.empty?
    ...
  else
    if resource.errors.messages[:reset_password_token]
      resource.errors.messages.delete(:reset_password_token)
      resource.errors.messages[:password_reset_link] = ["has already been used"]
    end
    respond_with resource
  end

More about Customizing Devise controllers

like image 27
Prakash Murthy Avatar answered Nov 11 '22 12:11

Prakash Murthy