Module: Devise::Models::DatabaseAuthenticatable

Extended by:
ActiveSupport::Concern
Defined in:
lib/devise/models/database_authenticatable.rb

Overview

Authenticatable Module, responsible for hashing the password and validating the authenticity of a user while signing in.

Options

DatabaseAuthenticatable adds the following options to devise_for:

* +pepper+: a random string used to provide a more secure hash. Use
  `rails secret` to generate new keys.

* +stretches+: the cost given to bcrypt.

* +send_email_changed_notification+: notify original email when it changes.

* +send_password_change_notification+: notify email when password changes.

Examples

User.find(1).valid_password?('password123')         # returns true/false

Defined Under Namespace

Modules: ClassMethods

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.required_fields(klass) ⇒ Object



54
55
56
# File 'lib/devise/models/database_authenticatable.rb', line 54

def self.required_fields(klass)
  [:encrypted_password] + klass.authentication_keys
end

Instance Method Details

#after_database_authenticationObject

A callback initiated after successfully authenticating. This can be used to insert your own logic that is only run after the user successfully authenticates.

Example:

def after_database_authentication
  self.update_attribute(:invite_code, nil)
end


168
169
# File 'lib/devise/models/database_authenticatable.rb', line 168

def after_database_authentication
end

#authenticatable_saltObject

A reliable way to expose the salt regardless of the implementation.



172
173
174
# File 'lib/devise/models/database_authenticatable.rb', line 172

def authenticatable_salt
  encrypted_password[0,29] if encrypted_password
end

#clean_up_passwordsObject

Set password and password confirmation to nil



72
73
74
# File 'lib/devise/models/database_authenticatable.rb', line 72

def clean_up_passwords
  @password = @password_confirmation = nil
end

#destroy_with_password(current_password) ⇒ Object

Destroy record when :current_password matches, otherwise returns error on :current_password. It also automatically rejects :current_password if it is blank.



146
147
148
149
150
151
152
153
154
155
156
# File 'lib/devise/models/database_authenticatable.rb', line 146

def destroy_with_password(current_password)
  result = if valid_password?(current_password)
    destroy
  else
    valid?
    errors.add(:current_password, current_password.blank? ? :blank : :invalid)
    false
  end

  result
end

#initialize(*args, &block) ⇒ Object



38
39
40
41
42
# File 'lib/devise/models/database_authenticatable.rb', line 38

def initialize(*args, &block)
  @skip_email_changed_notification = false
  @skip_password_change_notification = false
  super 
end

#password=(new_password) ⇒ Object

Generates a hashed password based on the given value. For legacy reasons, we use `encrypted_password` to store the hashed password.



61
62
63
64
# File 'lib/devise/models/database_authenticatable.rb', line 61

def password=(new_password)
  @password = new_password
  self.encrypted_password = password_digest(@password) 
end

#password_digest(password) ⇒ Object (protected)

Hashes the password using bcrypt. Custom hash functions should override this method to apply their own algorithm.

See github.com/plataformatec/devise-encryptable for examples of other hashing engines.



200
201
202
203
# File 'lib/devise/models/database_authenticatable.rb', line 200

def password_digest(password)
  return if password.blank?
  Devise::Encryptor.digest(self.class, password)
end

#send_email_changed_notificationObject

Send notification to user when email changes.



178
179
180
# File 'lib/devise/models/database_authenticatable.rb', line 178

def send_email_changed_notification
  send_devise_notification(:email_changed, to: email_before_last_save)
end

#send_email_changed_notification?Boolean (protected)

Returns:

  • (Boolean)


206
207
208
# File 'lib/devise/models/database_authenticatable.rb', line 206

def send_email_changed_notification?
  self.class.send_email_changed_notification && saved_change_to_email? && !@skip_email_changed_notification
end

#send_password_change_notificationObject

Send notification to user when password changes.



189
190
191
# File 'lib/devise/models/database_authenticatable.rb', line 189

def send_password_change_notification
  send_devise_notification(:password_change)
end

#send_password_change_notification?Boolean (protected)

Returns:

  • (Boolean)


216
217
218
# File 'lib/devise/models/database_authenticatable.rb', line 216

def send_password_change_notification?
  self.class.send_password_change_notification && saved_change_to_encrypted_password? && !@skip_password_change_notification
end

#skip_email_changed_notification!Object

Skips sending the email changed notification after_update



45
46
47
# File 'lib/devise/models/database_authenticatable.rb', line 45

def skip_email_changed_notification!
  @skip_email_changed_notification = true
end

#skip_password_change_notification!Object

Skips sending the password change notification after_update



50
51
52
# File 'lib/devise/models/database_authenticatable.rb', line 50

def skip_password_change_notification!
  @skip_password_change_notification = true
end

#update_with_password(params, *options) ⇒ Object

Update record attributes when :current_password matches, otherwise returns error on :current_password.

This method also rejects the password field if it is blank (allowing users to change relevant information like the e-mail without changing their password). In case the password field is rejected, the confirmation is also rejected as long as it is also blank.



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/devise/models/database_authenticatable.rb', line 83

def update_with_password(params, *options)
  if options.present?
    ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
      [Devise] The second argument of `DatabaseAuthenticatable#update_with_password`
      (`options`) is deprecated and it will be removed in the next major version.
      It was added to support a feature deprecated in Rails 4, so you can safely remove it
      from your code.
    DEPRECATION
  end

  current_password = params.delete(:current_password)

  if params[:password].blank?
    params.delete(:password)
    params.delete(:password_confirmation) if params[:password_confirmation].blank?
  end

  result = if valid_password?(current_password)
    update(params, *options)
  else
    assign_attributes(params, *options)
    valid?
    errors.add(:current_password, current_password.blank? ? :blank : :invalid)
    false
  end

  clean_up_passwords
  result
end

#update_without_password(params, *options) ⇒ Object

Updates record attributes without asking for the current password. Never allows a change to the current password. If you are using this method, you should probably override this method to protect other attributes you would not like to be updated without a password.

Example:

def update_without_password(params, *options)
  params.delete(:email)
  super(params)
end


125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/devise/models/database_authenticatable.rb', line 125

def update_without_password(params, *options)
  if options.present?
    ActiveSupport::Deprecation.warn <<-DEPRECATION.strip_heredoc
      [Devise] The second argument of `DatabaseAuthenticatable#update_without_password`
      (`options`) is deprecated and it will be removed in the next major version.
      It was added to support a feature deprecated in Rails 4, so you can safely remove it
      from your code.
    DEPRECATION
  end

  params.delete(:password)
  params.delete(:password_confirmation)

  result = update(params, *options)
  clean_up_passwords
  result
end

#valid_password?(password) ⇒ Boolean

Verifies whether a password (ie from sign in) is the user password.

Returns:

  • (Boolean)


67
68
69
# File 'lib/devise/models/database_authenticatable.rb', line 67

def valid_password?(password)
  Devise::Encryptor.compare(self.class, encrypted_password, password)
end