Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

devise change password not working (unknown attribute: current_password)

I'm not quite sure what I'm doing wrong but when a user tries to change their password on my app, it gives an error that current_password is an unknown attribute.

Here's my code:

def configure_devise_permitted_parameters
  registration_params = [:email, :password, :password_confirmation, :first_name, :last_name]

  if params[:action] == 'update'
    devise_parameter_sanitizer.for(:user_update) {
      |u| u.permit(registration_params << :current_password)
    }
  elsif params[:action] == 'create'
    devise_parameter_sanitizer.for(:sign_up) {
      |u| u.permit(registration_params)
    }
  end
end

class RegistrationsController < Devise::RegistrationsController
  def update
    account_update_params = devise_parameter_sanitizer.sanitize(:user_update)

    if account_update_params[:password].blank?
      account_update_params.delete("password")
      account_update_params.delete("password_confirmation")
      account_update_params.delete("current_password")
    end

    @user = User.find(current_user.id)
    if @user.update_attributes(account_update_params)
      set_flash_message :notice, :updated
      sign_in @user, bypass: true
      redirect_to after_update_path_for(@user)
    else
      render "edit"
    end
  end

what am i doing wrong here? what should I be doing with current_password to check it is correct before saving their new password correctly?

EDIT:stack trace

activerecord (4.0.3) lib/active_record/attribute_assignment.rb:47:in `rescue in _assign_attribute'
activerecord (4.0.3) lib/active_record/attribute_assignment.rb:42:in `_assign_attribute'
activerecord (4.0.3) lib/active_record/attribute_assignment.rb:29:in `block in assign_attributes'
activerecord (4.0.3) lib/active_record/attribute_assignment.rb:23:in `each'
activerecord (4.0.3) lib/active_record/attribute_assignment.rb:23:in `assign_attributes'
like image 852
Matthew Berman Avatar asked Apr 14 '14 18:04

Matthew Berman


3 Answers

Instead of calling @user.update_attributes(account_update_params) which blows up because current_password isn't a field in the database (at least not in the default schema), try calling update_resource(@user, account_update_params) which is provided by Devise::RegistrationsController which you're inheriting from. This in turn calls resource.update_with_password(params) which is provided by devise's DatabaseAuthenticatable module and checks the current_password before updating all the other params passed.

However, it looks like the standard DeviseController::RegistrationsController.update() would support what you want and more (e.g. handling if update needs a confirmation email); is there some reason why you need to override it?

like image 94
Tim Avatar answered Oct 30 '22 01:10

Tim


I had the same issue today with the following version of Ruby, Rails and Devise:

  • ruby-2.4.0
  • rails-5.1.4
  • devise-4.3.0

Here is my solution:

Create your registration controller in app/controllers/registrations_controller.rb

class RegistrationsController < Devise::RegistrationsController

  protected

  def update_resource(resource, params)
    # Require current password if user is trying to change password.
    return super if params["password"]&.present?

    # Allows user to update registration information without password.
    resource.update_without_password(params.except("current_password"))
  end
end

Tell Devise that you use your registrations controller defined in app/controllers/registrations_controller.rb.

# config/routes.rb
devise_for :users, controllers: { registrations: "registrations" }
like image 9
mnishiguchi Avatar answered Oct 30 '22 01:10

mnishiguchi


As of Devise 4,

When getting the unknown attribute for 'current_password', no need to play with the devise_parameter_sanitizer

Go into app/controllers/registrations_controller.rb

Change

def update_resource(resource, params)
    resource.update_without_password(params)
end

By

def update_resource(resource, params)
    resource.update_with_password(params)
end    
like image 3
Florian Mainguy Avatar answered Oct 29 '22 23:10

Florian Mainguy