使用rails进行敏捷Web开发

时间:2010-05-04 18:07:40

标签: ruby-on-rails ruby

这段代码来自使用rails book的敏捷Web开发..我不明白这部分代码...... User是一个名称,hashed_pa​​ssword,salt作为其字段的模型。但是在代码中他们提到了密码和密码确认,而模型中没有这样的字段。模型只有hashed_pa​​ssword。我确定错误与我同在。请清楚这个给我:)     用户模型有名称,hashed_pa​​ssword,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

4 个答案:

答案 0 :(得分:4)

attr_accessor用于为实例变量创建getter / setter方法。例如:

attr_accessor :foo

# is equivalent to

def foo
  @foo
end

def foo=(value)
  @foo = value
end

在您粘贴的代码中,def passworddef 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

相关问题