-
Notifications
You must be signed in to change notification settings - Fork 5.5k
How To: Allow users to edit their account without providing a password
By default, Devise allows users to change their password using the :registerable
module. But sometimes, developers want to create other actions that allow the user to change their information without requiring a password. In such cases, the best option is for you to manually override the Devise registrations controller:
class RegistrationsController < Devise::RegistrationsController
def update
# For Rails 4
account_update_params = devise_parameter_sanitizer.sanitize(:account_update)
# For Rails 3
# account_update_params = params[:user]
# required for settings form to submit when password is left blank
if account_update_params[:password].blank?
account_update_params.delete("password")
account_update_params.delete("password_confirmation")
end
@user = User.find(current_user.id)
if @user.update_attributes(account_update_params)
set_flash_message :notice, :updated
# Sign in the user bypassing validation in case his password changed
sign_in @user, :bypass => true
redirect_to after_update_path_for(@user)
else
render "edit"
end
end
end
In the example above, the user will be able to change any information they want. Including the password, e-mail etc. If you want users to update all information except the password itself, you can use update_without_password
provided by Devise and then proceed to implement the views. For example:
class RegistrationsController < Devise::RegistrationsController
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 update_without_password
# doesn't know how to ignore it
params[:user].delete(:current_password)
@user.update_without_password(params[:user])
end
if successfully_updated
set_flash_message :notice, :updated
# Sign in the user bypassing validation in case his password changed
sign_in @user, :bypass => true
redirect_to after_update_path_for(@user)
else
render "edit"
end
end
private
# check if we need password to update user data
# ie if password or email was changed
# extend this as needed
def needs_password?(user, params)
user.email != params[:user][:email] ||
params[:user][:password].present?
end
end
The above example takes care of validating the presence of users' current password if changing email or password. Otherwise it lets the request process without requiring current password.
Note that you need to tell Devise to route registrations to your new controller in config/routes.rb
:
devise_for :users, :controllers => { :registrations => "registrations" }
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.
With the introduction of Strong Parameters, you will need to specify permitted parameters in your overridden controllers. For example:
class ApplicationController < ActionController::Base
before_filter :configure_permitted_parameters, if: :devise_controller?
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) do |u|
u.permit(:first_name, :last_name, :username, :email, :password, :password_confirmation)
end
devise_parameter_sanitizer.for(:account_update) do |u|
u.permit(:first_name, :last_name, :username, :email, :password, :password_confirmation)
end
end
end
And then change update calls using the appropriate method below:
@user.update_with_password(devise_parameter_sanitizer.sanitize(:account_update))
@user.update_without_password(devise_parameter_sanitizer.sanitize(:account_update))
Refer to Devise README for lazy and non-lazy ways implementations of accomplishing this.
Add the following line in your Apotomo widget class:
include Devise::Controllers::Helpers
By default devise views uses methods such as resource and resource_name. If creating a new Registrations controller as recommended above for use with the default views generated by Devise, you may find it helpful to re-define these methods in a RegistrationsHelper:
module RegistrationsHelper
def resource_name
:user
end
def resource
@resource ||= User.new
end
def devise_mapping
@devise_mapping ||= Devise.mappings[:user]
end
end