Rails has_secure_password 保存成功但随后给出 nil 密码 - 验证失败
Rails has_secure_password saves successfully but then gives nil password - validation fails
我有一个带有 has_secure_password
和 validates :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
,影响了登录。
这是用户的代码,也许我在这里有什么问题?
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_password
,password
并不真正作为持久模型属性存在。它只是为了处理加密的原始密码而存在;之后它一直是 password_digest
(因此为什么 .password
returns nil
在现有对象上。
Rails 本身 'cheats' 在验证中,仅验证 password_digest
(GitHub):
的存在和长度
# 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
当有 clear-text 密码需要验证时,您的自定义验证在初始创建时工作正常。但在那之后,没有一个,所以你的存在检查失败(并且你的其他检查无关紧要)。要解决此问题,您可以将 on: create
添加到您的密码验证中,以便在新记录的情况下它们仅 运行。
我有一个带有 has_secure_password
和 validates :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
,影响了登录。
这是用户的代码,也许我在这里有什么问题?
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_password
,password
并不真正作为持久模型属性存在。它只是为了处理加密的原始密码而存在;之后它一直是 password_digest
(因此为什么 .password
returns nil
在现有对象上。
Rails 本身 'cheats' 在验证中,仅验证 password_digest
(GitHub):
# 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
当有 clear-text 密码需要验证时,您的自定义验证在初始创建时工作正常。但在那之后,没有一个,所以你的存在检查失败(并且你的其他检查无关紧要)。要解决此问题,您可以将 on: create
添加到您的密码验证中,以便在新记录的情况下它们仅 运行。