rails应用程序中一个model名为User,其中存放了用户名和对应的密码.User模式类中建立了1个虚拟属性password用来存放用户实际输入的密码;而最终数据库的密码需要计算password的散列后再存入,此外计算散列需要一个salt作为种子,该种子是随机生成的,生成后也保存在数据库中:
def generate_salt
self.salt = self.object_id.to_s + rand.to_s
end
模式User中需要验证用户输入各项的正确性,包括用户名不能为空,密码不能为空,两次输入的密码必须相同:
validates :name,presence:true,uniqueness:true
validates :password,confirmation:true
attr_accessor :password_confirmation
attr_reader :password
validate :password_must_be_present
def password_must_be_present
errors.add(:password,'Missing password') unless hashed_password.present?
end
其中单独写出password=的方法,在password被赋值时,计算salt和password哈希的值:
def self.encrypt_password(password,salt)
Digest::SHA2.hexdigest(password + "wibble" + salt)
end
#password is a virtual attribute
def password=(password)
@password = password
#An object is present if it's not blank,mean:
# 1.present? => true
# "".present? => false
# "hi".present? => true
if password.present?
generate_salt
self.hashed_password = self.class.encrypt_password(password,salt)
end
end
现在将以上功能重构,将计算salt和password哈希的代码放在model回调钩子before_save中,并将password_must_be_present删掉,加上
validates :password,presence:true
删除password=方法,并修改password属性为:
attr_accessor :password
然后新增before_save钩子:
before_save :calc_hash
def calc_hash
if self.password.present?
generate_salt
self.hashed_password = self.class.encrypt_password(password,salt)
end
end
在写回调函数的时候发现用:
class User
def before_save
end
end
方式写的钩子无法被回调,一定要用before_save的方式吗? :(