Reset Password Issue with Devise

2k views Asked by At

I'm using Devise in my Rails app and am running into an issue resetting passwords.

When I attempt to reset my password, I'm sent an email with a link to reset the password. After filling out the form with the new password, I get the error "The webpage has a redirect loop" in Chrome, and I get the following error in my logs:

Started GET "/users/password/edit?reset_password_token=[FILTERED]" for 127.0.0.1 at 2013-12-19 14:22:05 -0500
Processing by Devise::PasswordsController#edit as HTML
  Parameters: {"reset_password_token"=>"[FILTERED]"}
  User Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
Redirected to http://localhost:3000/users/password/edit?reset_password_token=JatMT1fE-fQwsCWsEdy6
Filter chain halted as :require_no_authentication rendered or redirected
Completed 302 Found in 1.8ms (ActiveRecord: 0.4ms)

I can't seem to find any information on how to fix this problem.

user.rb

class User < ActiveRecord::Base
 ...
 devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable,
         :token_authenticatable, :confirmable, :lockable
 ...
end

devise.rb

Devise.setup do |config|
  ...
  config.reset_password_within = 6.hours
  ...
end

routes.rb

Build::Application.routes.draw do
  devise_for :users, :controllers => {:registrations => :registrations}

  devise_scope :user do
      post 'registrations' => 'registrations#create', :as => 'register'
      post 'sessions' => 'sessions#create', :as => 'login'
      delete 'sessions' => 'sessions#destroy', :as => 'logout'
    end

 resources :users do
     match 'users/:id' => 'users#username'
     get 'validate_username', on: :collection
     get 'validate_email', on: :collection
     get 'edit_profile', on: :member
     get :projects, on: :member
     get :favorites, on: :member
     get :collections, on: :member
     member do
      get :follow
      get :unfollow
      get :following
      get :followers
     end
  end
end

registrations_controller.rb

class RegistrationsController < Devise::RegistrationsController

    skip_before_filter :verify_authenticity_token,
                     :if => Proc.new { |c| c.request.format == 'application/json' }

    respond_to :json

    def create
        user = User.new(params[:user])
        Rails.logger.info(user.inspect)
        # comment out following line to re-enable confirmation
        # resource.skip_confirmation!

        if user.save
          sign_in user
          render :status => 200,
               :json => { :success => true,
                          :info => "Registered",
                          :data => { :user => user,
                                     :auth_token => current_user.authentication_token } }
        else
            redirect_to new_user_registration_path, notice: user.errors.full_messages[0]
            Rails.logger.info(user.errors.inspect)
          # render :status => :unprocessable_entity,
          #        :json => { :success => false,
          #                   :info => resource.errors,
          #                   :data => {} }
        end
    end

    def update
        @user = User.find(current_user.id)
        successfully_updated = if needs_password?(@user, params)
            @user.update_with_password(params[:user])
        else
            # remove the virtual current_password attribute 
            params[:user].delete(:current_password)
            @user.update_without_password(params[:user])
        end

        if successfully_updated
            if params[:update_email]
                set_flash_message :alert, :signed_up_but_unconfirmed
                redirect_to after_update_path_for(@user)
            else            
                set_flash_message :notice, :updated
                sign_in @user, :bypass => true
                redirect_to after_update_path_for(@user)
            end
        else
            redirect_to :back, alert: resource.errors.full_messages[0]
        end
    end

        private

    # check if we need password to update user data
    def needs_password?(user,params)
        !params[:profile]
    end

    protected

    def after_update_path_for(resource)
        user_path(resource)
    end

end
2

There are 2 answers

0
guero64 On

I had exactly the same problem, except that I noticed that there was a repeated redirect to the password reset URL.

I think @Sergey Sokolov has the right answer, although I modified my after_sign_in_path:

def after_sign_in_path_for(resource_or_scope)
   if request.referer.include? "reset_password"
     root_path
   else
     request.referer
   end
end

so that in cases other than the password reset the user will return to the page that he or she signed in from. This avoids an issue of a user following a password reset link in an email.

I was also doing something very stupid while troubleshooting and remained logged in as a different user when I was resetting the password for a different user while testing. This causes very strange behavior.

0
Sergey Sokolov On

Check your after_sign_in_path_for in ApplicationController and add redirect to root_url (not :back or request.env['HTTP_REFERER']) if it is password edit request.