Skip to content

How To: Allow users to edit their account without providing a password

Araslanov Evgeny edited this page Jul 9, 2013 · 48 revisions

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
    # required for settings form to submit when password is left blank
    if params[:user][:password].blank?
      params[:user].delete("password")
      params[:user].delete("password_confirmation")
    end

    @user = User.find(current_user.id)
    if @user.update_attributes(params[:user])
      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.

Strong Parameters with Rails 4

With the induction 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, like so:

@user.update_with_password(devise_parameter_sanitizer.for(:account_update))

Refer to Devise README for lazy and non-lazy ways implementations of accomplishing this.

Using with Apotomo

Add the following line in your Apotomo widget class:

include Devise::Controllers::Helpers

Using a custom Registrations controller with Devise views

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
Clone this wiki locally