T开发者_如何学运维his code is from the agile web development with rails book.. I don't understand this part of the code... User is a model which has name,hashed_password,salt as its fields. But in the code they are mentioning about password and password confirmation, while there are no such fields in the model. Model has only hashed_password. I am sure mistake is with me. Please clear this for me :) User Model has name,hashed_password,salt. All the fields are strings
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
attr_accessor
is used to create getter/setter methods for an instance variable. For example:
attr_accessor :foo
# is equivalent to
def foo
@foo
end
def foo=(value)
@foo = value
end
In the code you pasted, def password
and def password=
are defined manually. However, I'm a bit confused by the use of:
attr_accessor :password_confirmation
validates_confirmation_of :foo
automatically creates a foo_confirmation
accessor, so this should be:
attr_accessor :password
validates_confirmation_of :password
Add a simple before_save
callback to encrypt the password and you're all done.
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
Since you don't want to store the password in the database in plaintext, you create a virtual attribute called password. You do this when you write:
def password=(pwd)
@password = pwd
return if pwd.blank?
create_new_salt
self.hashed_password = User.encrypted_password(self.password, self.salt)
end
That way, when you call password="wibble" it is actually encrypting "wibble" and storing the encrypted value in the database instead.
In the example, password_confirmation property is added to the model using the attr_accessor helper which sets up a getter and mutator for you in one line of code:
attr_accessor :password_confirmation
That one line is the same as if you had written this:
def password_confirmation
@password_confirmation
end
def password_confirmation=(pwd_conf)
@password_confirmation = pwd_conf
end
password's accessors are defined explicitly in the model:
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
These virtual attributes are defined in the model code, because they don't exist in the db table the model gets the rest of it's attributes from, because you don't want them stored in the db.
I was having the same question.
I found the item of validates_confirmation_of at Rails API website useful: http://ar.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#M000081.
精彩评论