-
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.
Make the following 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]
Notice 2: If you use the latest Devise with Strong Parameters, you should add this line to your ApplicationController.rb:
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
update_attrs = [:password, :password_confirmation, :current_password]
devise_parameter_sanitizer.permit :account_update, keys: update_attrs
end
end
Let's suppose that you don't want to allow users to # 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'
put 'users' => '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()
.
If you are using shared views for multiple models, you can use send("#{resource_name}_registration_path")
.
Notice: If you are using rails 4.0+ you should be using patch instead of put for updates. You should change the method in the form_tag residing in app/views/devise/registrations/edit.html.erb
and the routes.rb
file.
But sometimes, developers want to provide their custom actions that change the password. In such cases, the best option is for you to manually create a controller:
class UsersController < ApplicationController
before_action :authenticate_user!
def edit
@user = current_user
end
def update_password
@user = current_user
if @user.update(user_params)
# # the user by passing validation in case their password changed
bypass_sign_in(@user)
redirect_to root_path
else
render "edit"
end
end
private
def user_params
# NOTE: Using `strong_parameters` gem
params.require(:user).permit(:password, :password_confirmation)
end
end
If you are using several scopes, specify the one you are signing in:
bypass_sign_in @user, scope: :user
The route should be the following:
resource :user, only: [:edit] 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(user_params)
to @user.update_with_password(user_params)
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.