'Rails 4 'has_secure_password' validates a blank password and cannot perform conditional validations

I'm aware that has_secure_password adds validations for password and password_confirmation on the :create action.

When you create a new user, you have to enter a password (and confirmation) or else the user is invalid. That's the expected behavior and that's good.

When you want to update a user you can update select attributes without having to submit the password/confirmation. That's also good because I can update a user's name without the hassle of passwords.

However, I ran into a situation where I wanted to update a user's password and I require the user to enter their current password and then enter their new password and confirmation. The problem is when I ONLY enter the current password and submit the form, it passes all validation. Even though this may be the expected behavior, I think it's a very bad behavior because the password is NOT changed to a blank value even though it passes all validations. If I simply assume the code actually does what is "says" it does, then the user should now have a blank password.

class User < ActiveRecord::Base
  # model has password_digest field
  has_secure_password

  # has_secure_password automatically adds the following...
  # validates :password, presence: true, on: [:create]

  validates :password, length: { minimum: 8 }
end

class SettingsController < ApplicationController
  # POSTed from form with fields :current_password, :new_password, :new_password_confirmation
  def update_password
    if current_user.authenticate(params[:current_password])
      if current_user.update_attributes(password: params[:new_password], password_confirmation: params[:new_password_confirmation])
        flash.now[:notice] = "Successfully updated Password"
      else
        # Problem with new password (do nothing)
        flash.now[:error] = "Invalid new password or confirmation (nothing changed)"
        render "error"
      end
    else
      flash.now[:error] = "Must provide current password to change your password"
      render "error"
    end
  end
end

If you entered the current_password properly but left the new_password and new_password_confirmation BLANK, the controller code happily informs the user "Successfully updated Password".

But the user was not updated. The password was NOT set to a blank value. It wasn't changed.

I've tried to set conditionals on the password validations, but none of my attempts seem to work. What I'm trying to do is validate the presence and length of a password everytime the password field is submitted in the form (even if it's blank). I've googled this and none of the examples I've read work.

There has to be a standard solution that doesn't hack things. The desired functionality is everytime the password field is submitted in a form, the password validations should run and validate that the password isn't blank, meets the minimum length requirements, etc...

I've seen lots of folks say these work, but none of these seem to really work:

validates :password, length: ( minimum: 8 }, if: -> { password.present? }
validates :password, length: ( minimum: 8 }, allow_nil: true


Solution 1:[1]

There is a validation that allows the password blank if, and only if, the password and password_confirmation is blank. So, if you try to update the password and do not send the password confirmation, an error will be raised.

try this:

validates :password, length: { minimum: 8 }, allow_blank: true

Solution 2:[2]

I've confront the same problem so this is what solve my problem I add this ligne to my model

validates :password , presence: true 

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Bruno Paulino
Solution 2 Programer.new