Module: ActiveModel::SecurePassword::ClassMethods

Defined in:
lib/active_model/secure_password.rb

Instance Method Summary collapse

Instance Method Details

#has_secure_password(options = {}) ⇒ Object

Adds methods to set and authenticate against a BCrypt password. This mechanism requires you to have a password_digest attribute.

The following validations are added automatically:

  • Password must be present on creation

  • Password length should be less than or equal to 72 characters

  • Confirmation of password (using a password_confirmation attribute)

If password confirmation validation is not needed, simply leave out the value for password_confirmation (i.e. don’t provide a form field for it). When this attribute has a nil value, the validation will not be triggered.

For further customizability, it is possible to supress the default validations by passing validations: false as an argument.

Add bcrypt (~> 3.1.7) to Gemfile to use #has_secure_password:

gem 'bcrypt', '~> 3.1.7'

Example using Active Record (which automatically includes ActiveModel::SecurePassword):

# Schema: User(name:string, password_digest:string)
class User < ActiveRecord::Base
  has_secure_password
end

user = User.new(name: 'david', password: '', password_confirmation: 'nomatch')
user.save                                                       # => false, password required
user.password = 'mUc3m00RsqyRe'
user.save                                                       # => false, confirmation doesn't match
user.password_confirmation = 'mUc3m00RsqyRe'
user.save                                                       # => true
user.authenticate('notright')                                   # => false
user.authenticate('mUc3m00RsqyRe')                              # => user
User.find_by(name: 'david').try(:authenticate, 'notright')      # => false
User.find_by(name: 'david').try(:authenticate, 'mUc3m00RsqyRe') # => user


53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/active_model/secure_password.rb', line 53

def has_secure_password(options = {})
  # Load bcrypt gem only when has_secure_password is used.
  # This is to avoid ActiveModel (and by extension the entire framework)
  # being dependent on a binary library.
  begin
    require 'bcrypt'
  rescue LoadError
    $stderr.puts "You don't have bcrypt installed in your application. Please add it to your Gemfile and run bundle install"
    raise
  end

  include InstanceMethodsOnActivation

  if options.fetch(:validations, true)
    include ActiveModel::Validations

    # This ensures the model has a password by checking whether the password_digest
    # is present, so that this works with both new and existing records. However,
    # when there is an error, the message is added to the password attribute instead
    # so that the error message will make sense to the end-user.
    validate do |record|
      record.errors.add(:password, :blank) unless record.password_digest.present?
    end

    validates_length_of :password, maximum: ActiveModel::SecurePassword::MAX_PASSWORD_LENGTH_ALLOWED
    validates_confirmation_of :password, allow_blank: true
  end

  # This code is necessary as long as the protected_attributes gem is supported.
  if respond_to?(:attributes_protected_by_default)
    def self.attributes_protected_by_default #:nodoc:
      super + ['password_digest']
    end
  end
end