Thierry
Thierry

Reputation: 121

Devise update password route

On a rails app setup with Devise, i am trying to provide users with a form to change passwords.

i have followed the solution 3 from the Devise wiki:https://github.com/heartcombo/devise/wiki/How-To:-Allow-users-to-edit-their-password

and accordingly have in a user controller

class UsersController < Devise::RegistrationsController
  def update_password
    @user = current_user
    if @user.update(user_params)
      # Sign in the user by passing validation in case their password changed
      bypass_sign_in(@user)
      redirect_to root_path
    else
      render "edit"
    end
   end
end

routes.rb

devise_for :users,
           path: "", path_names: {
             sign_in: "login",
             sign_out: "logout",
             sign_up: "register",
             edit: "settings"
           },
           controllers: {
             registrations: "users",
             sessions: "users/sessions"
           }
resources :users do
 patch 'update_password'    
end

Rake routes gives me :

user_update_password_path   POST    (/:locale)/users/:user_id/update_password(.:format)     

users#update_password {:locale=>/fr|en|de/}

the link to access the menu is the following:

<%= link_to user_update_password_path(current_user) %>

in browser, that links directs me to :

http://localhost:3000/en/users/1/update_password

but I receive a Routing error

No route matches [GET] "/en/users/1/update_password"

When I wrap the

resources :users do
  resources :wishlists
  collection do
    patch 'update_password'
  end
end

the link_to send to

http://localhost:3000/1/password

Which results in the error

undefined local variable or method `user_update_password_path' for

<#:0x00007f86cfe48f10> Did you mean? user_password_path

however, rails routes shows:

update_password_users PATCH  (/:locale)/users/update_password(.:format)                                               users#update_password {:locale=>/fr|en|de/}

but a link_to

update_password_users_path

results in an error

Could not find devise mapping for path "/en/users/update_password". This may happen for two reasons:

1) You forgot to wrap your route inside the scope block. For example:

devise_scope :user do get "/some/route" => "some_devise_controller" end

2) You are testing a Devise controller bypassing the router. If so, you can explicitly tell Devise which mapping to use:

@request.env["devise.mapping"] = Devise.mappings[:user]

What have I missed ?

Upvotes: 0

Views: 5392

Answers (1)

Rafayet Monon
Rafayet Monon

Reputation: 1179

First of all in the solution 3 it says resource not resources. Watch the differences carefully between yours and the below one -

resource :user, only: [:edit] do
  collection do
    patch 'update_password'
  end
end

Second the like should direct to edit_user_path not update_password_user as that is the patch route.

Third, you have to add a edit action to your controller as the wiki suggests. And also a form for the action.

  before_action :authenticate_user!

  def edit
    @user = current_user
  end

and in app/views/users/edit.html.erb

<%= form_for(@user, :url => { :action => "update_password" } ) do |f| %>
  <div class="field">
    <%= f.label :password, "Password" %><br />
    <%= f.password_field :password, :autocomplete => "off"  %>
  </div>
  <div class="field">
    <%= f.label :password_confirmation %><br />
    <%= f.password_field :password_confirmation %>
  </div>
  <div class="action_container">
    <%= f.submit %>
  </div>
<% end %>

You missed lots of things. Try reading the wiki again.

Upvotes: 0

Related Questions