这段代码来自使用rails book的敏捷Web开发..我不明白这部分代码...... User是一个名称,hashed_password,salt作为其字段的模型。但是在代码中他们提到了密码和密码确认,而模型中没有这样的字段。模型只有hashed_password。我确定错误与我同在。请清楚这个给我:) 用户模型有名称,hashed_password,salt。所有字段都是字符串
require 'digest/sha1'
class User < ActiveRecord::Base
validates_presence_of :name
validates_uniqueness_of :name
attr_accessor :password_confirmation
validates_confirmation_of :password
validate :password_non_blank
def self.authenticate(name, password)
user = self.find_by_name(name)
if user
expected_password = encrypted_password(password, user.salt)
if user.hashed_password != expected_password
user = nil
end
end
user
end
def password
@password
end
def password=(pwd)
@password = pwd
return if pwd.blank?
create_new_salt
self.hashed_password = User.encrypted_password(self.password, self.salt)
end
private
def password_non_blank
errors.add(:password,"Missing password")if hashed_password.blank?
end
def create_new_salt
self.salt = self.object_id.to_s + rand.to_s
end
def self.encrypted_password(password, salt)
string_to_hash = password + "wibble" + salt
Digest::SHA1.hexdigest(string_to_hash)
end
end
答案 0 :(得分:4)
attr_accessor
用于为实例变量创建getter / setter方法。例如:
attr_accessor :foo
# is equivalent to
def foo
@foo
end
def foo=(value)
@foo = value
end
在您粘贴的代码中,def password
和def password=
是手动定义的。但是,我对使用以下内容感到困惑:
attr_accessor :password_confirmation
validates_confirmation_of :foo
会自动创建foo_confirmation
访问者,因此应该是:
attr_accessor :password
validates_confirmation_of :password
添加一个简单的before_save
回调来加密密码,你就完成了。
require 'digest/sha1'
class User < ActiveRecord::Base
# attrs
attr_accessor :password
# class methods
class << self
def encrypt(password, salt)
Digest::SHA1.hexdigest("--#{salt}--#{password}--");
end
end
# validation
validates_presence_of :name
validates_confirmation_of :password
# callbacks
before_save :encrypt_password
protected
def encrypt_password
return if password.blank?
if new_record?
self.salt = Digest::SHA1.hexdigest("--#{Time.now}--#{name}--")
end
self.encrypted_password = User.encrypt(password, salt)
end
end
答案 1 :(得分:3)
由于您不希望以明文形式将密码存储在数据库中,因此您需要创建一个名为password的虚拟属性。你写的时候这样做:
def password=(pwd)
@password = pwd
return if pwd.blank?
create_new_salt
self.hashed_password = User.encrypted_password(self.password, self.salt)
end
这样,当你调用password =“wibble”时,它实际上是加密“wibble”并将加密值存储在数据库中。
答案 2 :(得分:0)
在该示例中,使用attr_accessor帮助程序将password_confirmation属性添加到模型中,该帮助程序在一行代码中为您设置getter和mutator:
attr_accessor :password_confirmation
这一行和你写的一样:
def password_confirmation
@password_confirmation
end
def password_confirmation=(pwd_conf)
@password_confirmation = pwd_conf
end
密码的访问者在模型中明确定义:
def password
@password
end
def password=(pwd)
@password = pwd
return if pwd.blank?
create_new_salt
self.hashed_password = User.encrypted_password(self.password, self.salt)
end
这些虚拟属性在模型代码中定义,因为它们不存在于db表中,模型从其中获取其余属性,因为您不希望它们存储在db中。
答案 3 :(得分:0)
我有同样的问题。
我发现Rails API网站上的validates_confirmation_of项非常有用:http://ar.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#M000081。