Stenio Ferreira
Stenio Ferreira

Reputation: 357

Devise not calling correct controller for password reset

on my Ruby on Rails application I am using Devise for user auth.

My problem is with the password recovery by email - the email gets sent, but the link generated calls the UserController, instead of calling PasswordsController.

Here are my files:

Models/user.rb

class User < ActiveRecord::Base
devise :database_authenticatable, :registerable, :recoverable, :trackable, :omniauthable,      :omniauth_providers => [:google_oauth2]
...

views/devise/shared/_links.haml

...
=link_to "Forgot your password?", new_user_password_path(resource_name)
...

config/routes.rb

# user authentication
devise_for :users, :controllers => { :passwords => "devise/passwords", :omniauth_callbacks => "users/omniauth_callbacks" }

running rake routes

...
user_password      POST     /users/password(.:format)                                               devise/passwords#create
new_user_password  GET      /users/password/new(.:format)                                           devise/passwords#new
edit_user_password GET      /users/password/edit(.:format)                                          devise/passwords#edit
                   PATCH    /users/password(.:format)                                               devise/passwords#update
                   PUT      /users/password(.:format)                                               devise/passwords#update
...

email link

http://ugolanguage-testing.herokuapp.com/users/password/edit.3?reset_password_token=BHybmnzKnsK3L-xdvRGm

error message

2014-08-07T19:36:10.157145+00:00 heroku[router]: at=info method=GET path="/assets/webfonts/ss-standard-e13c0260a956bb5b5817b9fb5dc8de78.woff" host=ugolanguage-testing.herokuapp.com request_id=14f68207-c73a-41b6-84d6-e67709ffc4fc fwd="207.58.203.50" dyno=web.1 connect=1ms service=3ms status=304 bytes=1372
2014-08-07T19:36:20.834814+00:00 app[web.1]: Started GET "/users/password/edit.3?reset_password_token=[FILTERED]" for 207.58.203.50 at 2014-08-07 19:36:20 +0000
2014-08-07T19:36:21.225014+00:00 app[web.1]: Processing by UsersController#edit as 
2014-08-07T19:36:21.255102+00:00 app[web.1]: Completed 500 Internal Server Error in 30ms
2014-08-07T19:36:21.225027+00:00 app[web.1]:   Parameters: {"reset_password_token"=>"[FILTERED]", "id"=>"password"}
2014-08-07T19:36:22.739300+00:00 heroku[router]: at=info method=GET path="/users/password/edit.3?reset_password_token=BHybmnzKnsK3L-xdvRGm" host=ugolanguage-testing.herokuapp.com request_id=d0cd5b9a-3913-4e84-b69c-c7a2508dc019 fwd="207.58.203.50" dyno=web.1 connect=1ms service=1919ms status=500 bytes=1314
2014-08-07T19:36:22.737206+00:00 app[web.1]: 
2014-08-07T19:36:22.737213+00:00 app[web.1]:   app/controllers/users_controller.rb:55:in `check_admin'
2014-08-07T19:36:22.737211+00:00 app[web.1]: NoMethodError (undefined method `admin?' for nil:NilClass):

From the error message I get a sense Devise is expecting

<address to password controller><id><token>

Something is wrong, because it is assuming < id > is the "password" part of the address, and then it assumes the controller is given by "/user", which it is correctly calling the UserController as default.

Reading Devise documentation, I even added

devise_scope :user do
  get '/password/edit' => "password#edit"
end

which should only be necessary for custom actions of existing Devise controllers, but nothing has changed.

By the way, I do have a controllers/devise/password_controllers.rb

Any idea of what I can do to fix this? I might remove the "devise_for" from routes.rb and just do all the devise routes manually.

Additionaly, this is what is on

views/devise/mailer/reset_password_instructions.html.haml:

...
%p= link_to 'Change my password', edit_user_password_url(@resource, :reset_password_token => @token)
...

Upvotes: 1

Views: 1240

Answers (2)

Stenio Ferreira
Stenio Ferreira

Reputation: 357

thank you for your answer!

Yes, I had copied the code from Devise's github for passwords_controller.rb and placed it on the folder app/controllers/devise. I also tried without it and without the mention on devise_for at routes.rb.

I did find out the error though - on routes.rb, these lines were causing rails to route my request to the wrong place:

get "users/new" => "users#new", as: :new_user
post "users" => "users#create"
get "users/:id/edit" => "users#edit", as: :edit_user
patch "users/:id" => "users#update", as: :user

This was done by the previous developer, who installed Devise without the "recoverable" option. Will switch his code around so I can fall back to Devise's default routing behavior of "devise_for".

Thanks!

UPDATE:

even easier, just needed to switch the order.... now my routes.rb file looks like this

# user authentication
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }

get "users/new" => "users#new", as: :new_user
post "users" => "users#create"
get "users/:id/edit" => "users#edit", as: :edit_user
patch "users/:id" => "users#update", as: :user
delete "/users/:id" =>   "users#destroy"

Upvotes: 1

Moustafa Sallam
Moustafa Sallam

Reputation: 1132

in your config/routes.rb

# user authentication
devise_for :users, :controllers => { :passwords => "devise/passwords", :omniauth_callbacks => "users/omniauth_callbacks" }

it seems that you have instructed devise to use a new controller for passwords, did you create that controller, you asked devise to use a controller called passwords that exists in your app/controllers/devise instead the gem's controller.

Did you create this controller, what is the code inside it. if not, your route for devise should be:

# user authentication
devise_for :users, :controllers => { :omniauth_callbacks => "users/omniauth_callbacks" }

Upvotes: 1

Related Questions