Rails has_secure_password保存成功,但输入nil密码-验证失败

问题描述

我有一个has_secure_passwordvalidates :password,presence: true用户模型。

然后发生以下情况:

$ rails console

> u = User.create(name: 'user',password: 'password')
=> #<User id: ...
> u.password
=> 'password'
> u.save
=> true
> exit

然后我再次运行控制台,然后。

$ rails console
> u = User.find_by(name: 'user')
=> #<User id: ...
> u.password
=> nil
> u.valid?
=> false

我不明白为什么密码在第一次正确输入后就变为空。 在开发应用程序中也是如此,我可以使用omniauth_google登录用户,并使用SecureRandom.hex(15)创建密码。当我尝试注销并通过omniauth登录同一用户时,找到了该用户,但user.valid?给出了一个false,因为:passowrd神秘地变成了nil,破坏了登录。>

这是User的代码,也许我在这里出错了?

class User < ApplicationRecord
    has_many :notes
    has_many :goings
    has_many :cafes,through: :goings

    has_secure_password
    has_secure_password validations: false

    validates_uniqueness_of :name,{message: "%{value} name already exist"}
    validates :email,presence: { message: "%{attribute} must be given" }
  validates :password,presence: {
    message: 'You must enter a password'},length: {minimum: 2,message: 'Your password must contain at least 2 characters'
    }
    validates :name,presence: { message: "%{attribute} must be given" }

    def self.from_omniauth(response)
        User.find_or_create_by(uid: response[:uid],provider: response[:provider]) do |u|
            u.name = response[:info][:name]
            u.email = response[:info][:email]
            u.password = SecureRandom.hex(15)
        end
    end
end

解决方法

诀窍在于,对于has_secure_passwordpassword并不真正作为持久化模型属性存在。它仅用于处理原始密码以进行加密;之后便是password_digest(因此,.password为什么在现有对象上返回nil

在验证中“欺骗”自己,仅验证password_digestGitHub)的存在和长度:

# This ensures the model has a password by checking whether the password_digest
# is present,so that this works with both new and existing records. However,# when there is an error,the message is added to the password attribute instead
# so that the error message will make sense to the end-user.
validate do |record|
  record.errors.add(:password,:blank) unless record.password_digest.present?
end

validates_length_of :password,maximum: ActiveModel::SecurePassword::MAX_PASSWORD_LENGTH_ALLOWED

当存在要验证的明文密码时,您的自定义验证在初始创建时可以正常工作。但是在那之后,没有一个,因此您的状态检查失败(其他检查无关紧要)。要解决此问题,您可以将on: create添加到密码验证中,以便仅在新记录的情况下运行。