针对 Rails 中的空白密码进行验证

Validating against blank password in Rails

我为我的 User 模型添加了密码密码验证:

validates :password, presence: true
validates :password, confirmation: { case_sensitive: true }

但是当我想更新 users 上的其他字段时,这些验证使交易无效,因为 password 不存在。

通过一些研究,我意识到如果 password 不存在,我可以跳过这些验证:

validates :password, presence: true, if: :validate_password?
validates :password, confirmation: { case_sensitive: true }, if: :validate_password?


def validate_password?
  password.present? || password_confirmation.present?
end

但是,现在当我提交空白密码和密码确认时,validate_password? returns false。我真的不明白发生了什么,因为

@user.update_attributes(password_reset_edit_params) returns true

其中

password_reset_edit_params<ActionController::Parameters {"password"=>"", "password_confirmation"=>""} permitted: true>

但里面

def validate_password?
  password.present? || password_confirmation.present?
end

passwordpassword_confirmation 评估为 nil,我的 @user 密码没有更新为空字符串。

我应该提到我正在使用 Bcrypt,@user.password 实际上总是会评估为 nil,而 password_digest 可用。

那么解决方法是什么?最后我想我的问题很简单:

如何在我不尝试提交密码时忽略密码验证,但在提交空字符串时允许这些验证?

我突然想到我可以在控制器中添加一个不允许传递空字符串的条件,但是必须有一个巧妙的方法来解决这个问题。

非常感谢任何帮助。谢谢!

在 Rails 中,您不是在验证参数,而是在验证模型。

不要"skip validation if the password is not present"。这就是验证的目的。验证旨在验证 模型 ,而不是参数。如果模型的密码为空,并且需要密码,则该模型无效。总是。

but then when I wanted to update other fields on users, those validations were rendering the transaction invalid, as password was not present.

这不是因为密码不存在,而是因为用户实例中没有密码。它的工作方式应该是:

  1. 使用密码创建用户并验证:User.create(name: "Me", password: "something that isn't nil")
  2. 用户已更新:User.update(name: "New name") # password is inside the model still so it is still valid

这就是它的工作原理。如果您希望用户能够拥有零/空密码,那么您不应该尝试在模型中放置存在验证。

如果你使用 Bcrypt 和 digest,你可以在你的模型中使用,例如

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

在这种情况下,验证仅适用于设置和更改密码。

如果不修改密码就不需要输入密码。

另一种方式

validates :password, presence: true, on: :create

最终我只是在用户模型上验证密码格式和确认:

validates :password,  confirmation: true,
                      length: {within: 6..40},
                      allow_blank: true

并根据控制器中的空白密码/password_confirmation 清理输入数据。

if password_reset_edit_params[:password].blank? || password_reset_edit_params[:password_confirmation].blank?
      @user.errors[:password] << "can't be blank" if password_reset_edit_params[:password].blank?
      @user.errors[:password_confirmation] << "can't be blank" if password_reset_edit_params[:password_confirmation].blank?
      render 'edit'