开发者

Agile web development with rails

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜