设计 - 未初始化的常量User :: PasswordHistory

时间:2011-08-15 11:45:30

标签: ruby-on-rails ruby-on-rails-3 rubygems devise

我正在使用rails 3应用程序并且已经实现了设计。我有它工作,现在我希望扩展它,以便用户不能多次使用旧密码。在github上找到了这个功能,这对我的惊喜很好。 Disallow previously passwords - Git Hub

我认为这很直接,但显然不是。我的代码如下所示:

create_passwrod_histories.rb

class CreatePasswordHistories < ActiveRecord::Migration
  def self.up
    create_table(:password_histories) do |t|
      t.integer :user_id
      t.string  :encrypted_password
      t.timestamps
    end
  end

  def self.down
    drop_table :password_histories
  end
end

User.rb

class User < ActiveRecord::Base
  include ActiveModel::Validations
  has_many :roles_users
  has_many :roles, :through => :roles_users
  has_many :projects
  has_many :password_histories
  after_save :store_digest


  # authorization include this in whichever model that will use ACL9
  acts_as_authorization_subject
   def has_role?(role_name, object=nil)
    !! if object.nil?
      self.roles.find_by_name(role_name.to_s) ||
      self.roles.member?(get_role(role_name, nil))
    else
      method = "is_#{role_name.to_s}?".to_sym
      object.respond_to?(method) && object.send(method, self)
    end
  end



  def login(user)
    post_via_redirect user_session_path, 'user[username]' => user.username, 'user[password]' => user.password
  end
  # Include default devise modules. Others available are:
  # :token_authenticatable, :encryptable, :confirmable, :lockable, :timeoutable and :omniauthable #:registerable,
  devise :database_authenticatable, :recoverable, :rememberable, :trackable, :validatable, :timeoutable
  acts_as_authorization_subject  :association_name => :roles
  attr_accessor :login
  # Setup accessible (or protected) attributes for your model
  attr_accessible :id, :login, :username, :full_name, :email, :password, :password_confirmation, :remember_me, :role_ids

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

  validates_presence_of :username, :full_name
  validates_format_of :username, :with => /^[-\w\._@]+$/i, :allow_blank => true, :message => "should only contain letters, numbers, or . - _ @"
  validates_length_of :username, :minimum => 1, :allow_blank => true
  validates_uniqueness_of :username, :email
  validates :email, :presence => true,
                    :format   => { :with => email_regex }
  validates :password, :unique_password => true

  def self.find_for_database_authentication(warden_conditions)
   conditions = warden_conditions.dup
   login = conditions.delete(:login)
   where(conditions).where(["lower(username) = :value OR lower(email) = :value", { :value => login.downcase }]).first
  end

  private

  def store_digest
    if encrypted_password_changed?
      PasswordHistory.create(:user => self, :encrypted_password => encrypted_password)
    end
  end


end

unique_password_validator.rb

require 'bcrypt'
class UniquePasswordValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    record.password_histories.each do |ph|
      bcrypt = ::BCrypt::Password.new(ph.encrypted_password)
      hashed_value = ::BCrypt::Engine.hash_secret([value, Devise.pepper].join, bcrypt.salt)
      record.errors[attribute] << "has been used previously." and return if hashed_value == ph.encrypted_password
    end
  end
end

然后我运行我的应用并尝试使用相同的密码。然后它会抛出以下错误uninitialized constant User::PasswordHistory

1 个答案:

答案 0 :(得分:2)

我可以从代码中看到为什么会发生这种情况的唯一方法是,如果您没有PasswordHistory模型对象。来自Github的代码实际上没有明确告诉你这样做,但你肯定需要它。所以,也许您创建并运行了迁移但忘记创建模型,如:

class PasswordHistory < ActiveRecord::Base
...
end