Upgrading to devise 3.1 => getting Reset password token is invalid

Andreas Lyngstad picture Andreas Lyngstad · Sep 6, 2013 · Viewed 16.5k times · Source

Solution

Thanks to this gist form Steven Harman, I got it working. devise_mail_helpers.rb

module Features
  module MailHelpers

    def last_email
      ActionMailer::Base.deliveries[0]
    end

    # Can be used like:
    #  extract_token_from_email(:reset_password)
    def extract_token_from_email(token_name)
      mail_body = last_email.body.to_s
      mail_body[/#{token_name.to_s}_token=([^"]+)/, 1]
    end

  end
end

I added the file devise_mail_helpers.rb to the same folder as the features specs and wrote this spec.

require 'devise_mail_helpers.rb'
include Features
include MailHelpers
describe "PasswordResets" do
  it "emails user when requesting password reset" do
    user = FactoryGirl.create(:user)
    visit root_url
    find("#login_link").click
    click_link "Forgot your password?"
    fill_in "Email", :with => user.email
    click_button "Send instructions"
    current_path.should eq('/users/sign_in')
    page.should have_content("You will receive an email with instructions about how to reset your password in a few minutes.")
    last_email.to.should include(user.email)
    token = extract_token_from_email(:reset_password) # Here I call the MailHelper form above
    visit edit_password_url(reset_password_token: token)
    fill_in "user_password", :with => "foobar"
    fill_in "user_password_confirmation", :with => "foobar1"
    find('.signup_firm').find(".submit").click
    page.should have_content("Password confirmation doesn't match Password")
  end
 end

This takes care of the specs, to make it work in the browser look at Dave's answer below.

Original Question

In my rails 4 app, I've upgraded devise to 3.1 and ran rails s, then I got this:

`raise_no_secret_key': Devise.secret_key was not set. 
 Please add the following to your Devise initializer: (RuntimeError)
 config.secret_key = '--secret--'

I added the secret key to the devise initializer.

After this I get the following error when I try to reset the password

Reset password token is invalid

It seems like the token that gets sent in the email is not correct. Everything else is working. I logging in and out like a warm knife trough butter.

Update

Now I guess that it's got to be something with the encryption of the reset_password_token Here from the feature spec:

user = FactoryGirl.create(:user, 
 :reset_password_token => "something", 
 :reset_password_sent_at => 1.hour.ago)
visit edit_password_url(user, :reset_password_token => 
  user.reset_password_token)
fill_in "user_password", :with => "foobar"
click_button "Change my password"
page.should have_content("Password confirmation doesn't match Password")

the error occured is:

Failure/Error: page.should have_content
("Password confirmation doesn't match Password")        
expected to find text "Password confirmation doesn't match Password" in 
"Reset password token is invalid"

Any ideas on what I am missing?

Answer

David Elner picture David Elner · Sep 7, 2013

You commented on my similar question a bit ago, and I found an answer that might help you as well.

Upgrading to Devise 3.1.0 left some 'cruft' in a view that I hadn't touched in a while. According to this blog post, you need to change your Devise mailer to use @token instead of the old @resource.confirmation_token.

Find this in app/views/<user>/mailer/reset_password_instructions.html.erb and change it to something like:

<p>Hello <%= @resource.email %>!</p>
<p>Someone has requested a link to change your password, and you can do this through the link below.</p>
<p><%= link_to 'Change my password', edit_password_url(@resource, :reset_password_token => @token) %></p>
<p>If you didn't request this, please ignore this email.</p>
<p>Your password won't change until you access the link above and create a new one.</p>

This should fix any token-based confirmation problems you're having. This is likely to fix any unlock or confirmation token problems as well.