我在用户模型中使用has_secure_password。我已经为用户实现了一种在模型之外更改密码的方法,但是为了保持干燥,我正在尝试将控制器所需的验证移动到模型中。
用户模型如下所示:
class User
include Mongoid::Document
include ActiveModel::SecurePassword
has_secure_password
field: :password_digest, type: String
attr_accessible :password, :password_confirmation, :current_password
end
用户通过提交以下内容来更改密码:
user[current_password] - Currently stored password
user[password] - New password
user[password_confirmation] - New password confirmation
我在当前用户的User模型上使用update_attributes(params [:user])。我的问题是调用update_attributes在使用验证之前更新了password_digest,因此以下代码将不起作用:
def password_validation_required?
password_digest.blank? || !password.blank? || !password_confirmation.blank?
end
validate(on: :update, if: :password_validation_required?) do
unless authenticate(current_password)
add(:current_password, 'invalid password')
end
end
身份验证是基于从用户[密码]生成的新密码_digest进行身份验证。是否有一种优雅的方式来访问旧的password_digest值进行身份验证?我的一个想法是重新查询用户以获得对将使用旧的password_digest值进行身份验证的另一个身份验证方法的访问权限。问题在于它不是一个干净的解决方案。
答案 0 :(得分:1)
我认为这个比@ Parazuce的更清洁:
validate :validates_current_password
private
def validates_current_password
return if password_digest_was.nil? || !password_digest_changed?
unless BCrypt::Password.new(password_digest_was) == current_password
errors.add(:current_password, "is incorrect")
end
end
答案 1 :(得分:0)
password_digest字段有与之关联的ActiveModel :: Dirty方法,所以我决定选择:
validate(on: :update, if: :password_validation_required?) do
unless BCrypt::Password.new(password_digest_was) == current_password
errors.add(:current_password, "is incorrect")
end
end
这可以防止需要使用额外的逻辑覆盖password=
,如果使用其他功能password=
,将来可能会引入错误。