-
Notifications
You must be signed in to change notification settings - Fork 5.5k
How To: Allow users to edit their password
By default, Devise allows users to change their password using the registerable module.
Here we are going to provide a few solutions on how to allow users to change their password.
Solution 1.
Just make such link in your view:
<%= link_to "Change your password", edit_user_registration_path %>
Notice: This'll work if you didn't do any modification in your routes.rb file such as
devise_for :users, :skip => [:registrations]
Solution 2.
Lets suppose that you don't want to allow to sign up but you want to allow to change password for registered users. Just paste this code in routes.rb:
devise_for :users, :skip => [:registrations]
as :user do
get 'users/edit' => 'devise/registrations#edit', :as => 'edit_user_registration'
patch 'users/:id' => 'devise/registrations#update', :as => 'user_registration'
end
And then you can make such link in your view:
= link_to "Change your password", edit_user_registration_path
Notice: you will need to update default devise views accordingly, i.e. in app/views/devise/registrations/edit.html.erb
change registration_path(resource_name)
to user_registration_path(resource)
Solution 3.
But sometimes, developers want to provide their custom actions that change the password. In such cases, the best option is for you to create manually a controller:
class UsersController < ApplicationController
def edit
@user = current_user
end
def update_password
@user = User.find(current_user.id)
if @user.update_attributes(user_params)
# Sign in the user by passing validation in case his password changed
sign_in @user, :bypass => true
redirect_to root_path
else
render "edit"
end
end
private
def user_params
# NOTE: Using `strong_parameters` gem
params.required(:user).permit(:password, :password_confirmation)
end
end
The route should be the following:
resource :user, only: [:show] do
collection do
patch 'update_password'
end
end
And then proceed to implement the view, as below:
<%= 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 %>
To use "confirm_password" field to force user to enter old password before updating with the new one: Change @user.update_attributes(params[:user])
to @user.update_with_password(params[:user])
in the controller along with adding :current_password
to the permitted parameters, then and add the following to the view code:
<div class="field">
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br />
<%= f.password_field :current_password %>
</div>
Remember, Devise models are like any model in your application. If you want to provide custom behavior, just implement new actions and new controllers. Don't try to bend Devise.