Ruby on Rails:当我在admin属性上使用"toggle"方法时,为什么用户的加密密码会在数据库中被更改?

Bea*_*red 2 ruby ruby-on-rails ruby-on-rails-3

我刚刚完成了Hartl的Rails教程书,我在我的第一个rails应用程序中使用了他的帐户认证逻辑.然而,当我提出一个新的用户帐户,并通过在控制台切换admin属性设置为管理员帐户(例如User.find(5).toggle(:管理员)),存储在数据库加密的密码得到修改.为什么?

这是用户模型逻辑......

class User < ActiveRecord::Base

  #virtual attributes
  attr_accessor :password           

  #attrs modifiable by the outside world
  attr_accessible :name, :email, :password, :password_confirmation    

  email_regex = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i

  #validations
  validates :name,  :presence => true,
                    :length   => { :maximum => 50 }
  validates :email, :presence => true,
                    :format   => { :with => email_regex },
                    :uniqueness => true
  validates :password,  :presence     => true,
                        :confirmation => true,
                        :length       => { :within => 6..40 }

  #class method that authenticates a user, used to create a session cookie
  def self.authenticate(email, submitted_password)
    user = find_by_email(email)
    return nil if user.nil?
    return user if user.has_password?(submitted_password)
  end

  #used to authenticate a signed user from a signed cookie 
  def self.authenticate_with_salt(id, cookie_salt)
    user = find_by_id(id)
    return nil if user.nil?
    return user if user.salt == cookie_salt
  end

  #callback that occurs before a record is successfully saved (meaning it has a valud password)                      
  before_save :encrypt_password

  def has_password?(submitted_password)
    encrypted_password == encrypt(submitted_password)
  end

  private

    #self keyword is required when assigning to a instance attribute
    def encrypt_password
      self.salt = make_salt if new_record?
      self.encrypted_password = encrypt(password)
    end

    def encrypt(string)
      secure_hash("#{salt}--#{string}")
    end

    def make_salt
      secure_hash("#{Time.now.utc}--#{password}")      
    end

    def secure_hash(string)
      Digest::SHA2.hexdigest(string)
    end
end
Run Code Online (Sandbox Code Playgroud)

这就是行为的样子......

ruby-1.9.2-p180 :018 > User.last
 => #<User id: 12, name: "Test User A", email: "testusera@website.com", created_at: "2011-03-28 17:47:42", updated_at: "2011-03-28 17:47:42", salt: "23ca99e9848336a078e05ce9a8d904f9dfdff30dc7a38586f22...", admin: false, monthly_score: nil, encrypted_password: "50d17e6d6b581cfcfe84b61feb318705978cdf6c435626d10aa..."> 

ruby-1.9.2-p180 :019 > User.last.toggle!(:admin)
 => true 

ruby-1.9.2-p180 :020 > User.last
 => #<User id: 12, name: "Test User A", email: "testusera@website.com", created_at: "2011-03-28 17:47:42", updated_at: "2011-03-28 17:49:06", salt: "23ca99e9848336a078e05ce9a8d904f9dfdff30dc7a38586f22...", admin: true, monthly_score: nil, encrypted_password: "5d6e17f7aa73925a0099da45807f5994fa8c368a5a12d187a7d...">
Run Code Online (Sandbox Code Playgroud)

非常感谢你的帮助!

fl0*_*00r 5

尝试更改您的before_save方法:

def encrypt_password
  if password.present?
    self.salt = make_salt if new_record?
    self.encrypted_password = encrypt(password)
  end
end
Run Code Online (Sandbox Code Playgroud)

UPD.或者你可以把它缩短一点

def encrypt_password
  self.salt = make_salt if new_record?
  self.encrypted_password = encrypt(password) if password.present?
end
Run Code Online (Sandbox Code Playgroud)