3
votes

I have some custom fields in for my Devise registrations controller, and set this up in Application_controller:

def configure_permitted_parameters
  devise_parameter_sanitizer.for(:account_update) { |u| u.permit(:first_name, :last_name, :email, :password, :password_confirmation, :current_password, :remember_me) }
end

Here is my edit registration form:

<%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %>
  <%= f.error_notification %>
<div class="form-inputs">
    <%= f.input :email, required: true, autofocus: true, placeholder: "Email" %>
<br>
<%= f.input :password, autocomplete: "off", hint: "Leave blank if you are not changing your password", required: false, placeholder: "Password" %>
<br>
<%= f.input :password_confirmation, required: false, placeholder: "Password Confirmation" %>



  <div class="form-actions">
     <%= link_to "Back to Home Page", user_landings_path, :class => 'btn btn-success' %>
    <%= f.submit 'Update', :class => 'btn btn-primary' %>
  </div>
<% end %>

The email change saved, but not the password.

Any tips?

Edit:

I also am bypassing the requirement that users enter in their current password to update their account, if that matters:

class RegistrationsController < Devise::RegistrationsController

protected

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

end

2
What does your log say? What params are being passed?MarsAtomic
How do I access logs with params?Steve
Every SQL operation is logged, and you can see the parameters that are being written/read. Look in development.log or just look at your console.MarsAtomic
All it shows for what was entered in the password fields is : "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"Steve
'update_without_password' update the resource without password, remove this from your controller,for more see github.com/plataformatec/devise/wiki/…Gaurav Gupta

2 Answers

2
votes

I have solved this in the past by manually assigning the password to the resource. Overwrite the devise method update_resource in your RegistrationsController (or wherever you may need it). This will insure that the password is updated if it is passed in the params, and then handle any other attributes.

  def update_resource(resource, params)
    if params[:password]
      resource.password = params[:password]
      resource.password_confirmation = params[:password_confirmation]
    end

    resource.update_without_password(params)
  end

It's a little bit of a monkey patch but gets the job done.

0
votes

This behaviour is exactly what Divises authors want it to be. They do not want user to change the password without presenting current one because it's possible security issue. Say you leave your machine unlocked while went for coffee and your roommate changed password on the website you been logged in. Not cool, right? So as I decided for myself the best thing to do is to separate edit profile and change password actions, so you can change profile without presenting current_password, but for password change you should present it.

The exact reason why password not updating in Devises update_without_password method implementation (note params.delete and authors' comment):

# Updates record attributes without asking for the current password.
# Never allows a change to the current password. If you are using this
# method, you should probably override this method to protect other
# attributes you would not like to be updated without a password.

def update_without_password(params, *options)
  params.delete(:password)
  params.delete(:password_confirmation)

  result = update_attributes(params, *options)
  clean_up_passwords
  result
end

Now note how they make password optional in update_with_password method (note id params[:password].blank? block):

def update_with_password(params, *options)
  current_password = params.delete(:current_password)

  if params[:password].blank?
    params.delete(:password)
    params.delete(:password_confirmation) if params[:password_confirmation].blank?
  end

  result = if valid_password?(current_password)
    update_attributes(params, *options)
  else
    self.assign_attributes(params, *options)
    self.valid?
    self.errors.add(:current_password, current_password.blank? ? :blank : :invalid)
    false
  end

  clean_up_passwords
  result
end

So exact solution to your question is to override update_without_params method to remove password from params conditionally as they do in update_with_password method. But personally I don't advise to do this because of possible security issue. Better solution in my opinion is to separate views of profile edit and password change.