Module: Devise::Models::Authenticatable

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

Overview

Authenticatable module. Holds common settings for authentication.

Options

Authenticatable adds the following options to devise:

* +authentication_keys+: parameters used for authentication. By default [:email].

* +http_authentication_key+: map the username passed via HTTP Auth to this parameter. Defaults to
  the first element in +authentication_keys+.

* +request_keys+: parameters from the request object used for authentication.
  By specifying a symbol (which should be a request method), it will automatically be
  passed to find_for_authentication method and considered in your model lookup.

  For instance, if you set :request_keys to [:subdomain], :subdomain will be considered
  as key on authentication. This can also be a hash where the value is a boolean specifying
  if the value is required or not.

* +http_authenticatable+: if this model allows http authentication. By default false.
  It also accepts an array specifying the strategies that should allow http.

* +params_authenticatable+: if this model allows authentication through request params. By default true.
  It also accepts an array specifying the strategies that should allow params authentication.

* +skip_session_storage+: By default Devise will store the user in session.
  By default is set to skip_session_storage: [:http_auth].

active_for_authentication?

After authenticating a user and in each request, Devise checks if your model is active by calling model.active_for_authentication?. This method is overwritten by other devise modules. For instance, :confirmable overwrites .active_for_authentication? to only return true if your model was confirmed.

You can overwrite this method yourself, but if you do, don’t forget to call super:

def active_for_authentication?
  super && special_condition_is_valid?
end

Whenever active_for_authentication? returns false, Devise asks the reason why your model is inactive using the inactive_message method. You can overwrite it as well:

def inactive_message
  special_condition_is_valid? ? super : :special_condition_is_not_valid
end

Defined Under Namespace

Modules: ClassMethods

Constant Summary collapse

UNSAFE_ATTRIBUTES_FOR_SERIALIZATION =
[:encrypted_password, :reset_password_token, :reset_password_sent_at,
:remember_created_at, :sign_in_count, :current_sign_in_at, :last_sign_in_at, :current_sign_in_ip,
:last_sign_in_ip, :password_salt, :confirmation_token, :confirmed_at, :confirmation_sent_at,
:remember_token, :unconfirmed_email, :failed_attempts, :unlock_token, :locked_at]

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.required_fields(klass) ⇒ Object



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

def self.required_fields(klass)
  []
end

Instance Method Details

#active_for_authentication?Boolean

Returns:

  • (Boolean)


90
91
92
# File 'lib/devise/models/authenticatable.rb', line 90

def active_for_authentication?
  true
end

#apply_to_attribute_or_variable(attr, method) ⇒ Object (protected)



215
216
217
218
219
220
221
222
223
224
225
226
227
# File 'lib/devise/models/authenticatable.rb', line 215

def apply_to_attribute_or_variable(attr, method)
  if self[attr]
    self[attr] = self[attr].try(method)

  # Use respond_to? here to avoid a regression where globally
  # configured strip_whitespace_keys or case_insensitive_keys were
  # attempting to strip or downcase when a model didn't have the
  # globally configured key.
  elsif respond_to?(attr) && respond_to?("#{attr}=")
    new_value = send(attr).try(method)
    send("#{attr}=", new_value)
  end
end

#authenticatable_saltObject



98
99
# File 'lib/devise/models/authenticatable.rb', line 98

def authenticatable_salt
end

#devise_mailerObject (protected)



130
131
132
# File 'lib/devise/models/authenticatable.rb', line 130

def devise_mailer
  Devise.mailer
end

#downcase_keysObject (protected)



207
208
209
# File 'lib/devise/models/authenticatable.rb', line 207

def downcase_keys
  self.class.case_insensitive_keys.each { |k| apply_to_attribute_or_variable(k, :downcase) }
end

#inactive_messageObject



94
95
96
# File 'lib/devise/models/authenticatable.rb', line 94

def inactive_message
  :inactive
end

#inspectObject

Redefine inspect using serializable_hash, to ensure we don’t accidentally leak passwords into exceptions.



121
122
123
124
125
126
# File 'lib/devise/models/authenticatable.rb', line 121

def inspect
  inspection = serializable_hash.collect do |k,v|
    "#{k}: #{respond_to?(:attribute_for_inspect) ? attribute_for_inspect(k) : v.inspect}"
  end
  "#<#{self.class} #{inspection.join(", ")}>"
end

#send_devise_notification(notification, *args) ⇒ Object (protected)

This is an internal method called every time Devise needs to send a notification/mail. This can be overridden if you need to customize the e-mail delivery logic. For instance, if you are using a queue to deliver e-mails (active job, delayed job, sidekiq, resque, etc), you must add the delivery to the queue just after the transaction was committed. To achieve this, you can override send_devise_notification to store the deliveries until the after_commit callback is triggered.

The following example uses Active Job’s ‘deliver_later` :

class User
  devise :database_authenticatable, :confirmable

  after_commit :send_pending_devise_notifications

  protected

  def send_devise_notification(notification, *args)
    # If the record is new or changed then delay the
    # delivery until the after_commit callback otherwise
    # send now because after_commit will not be called.
    # For Rails < 6 use `changed?` instead of `saved_changes?`.
    if new_record? || saved_changes?
      pending_devise_notifications << [notification, args]
    else
      render_and_send_devise_message(notification, *args)
    end
  end

  private

  def send_pending_devise_notifications
    pending_devise_notifications.each do |notification, args|
      render_and_send_devise_message(notification, *args)
    end

    # Empty the pending notifications array because the
    # after_commit hook can be called multiple times which
    # could cause multiple emails to be sent.
    pending_devise_notifications.clear
  end

  def pending_devise_notifications
    @pending_devise_notifications ||= []
  end

  def render_and_send_devise_message(notification, *args)
    message = devise_mailer.send(notification, self, *args)

    # Deliver later with Active Job's `deliver_later`
    if message.respond_to?(:deliver_later)
      message.deliver_later
    # Remove once we move to Rails 4.2+ only, as `deliver` is deprecated.
    elsif message.respond_to?(:deliver_now)
      message.deliver_now
    else
      message.deliver
    end
  end

end


197
198
199
200
201
202
203
204
205
# File 'lib/devise/models/authenticatable.rb', line 197

def send_devise_notification(notification, *args)
  message = devise_mailer.send(notification, self, *args)
  # Remove once we move to Rails 4.2+ only.
  if message.respond_to?(:deliver_now)
    message.deliver_now
  else
    message.deliver
  end
end

#serializable_hash(options = nil) ⇒ Object

Redefine serializable_hash in models for more secure defaults. By default, it removes from the serializable model all attributes that are not accessible. You can remove this default by using :force_except and passing a new list of attributes you want to exempt. All attributes given to :except will simply add names to exempt to Devise internal list.



106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/devise/models/authenticatable.rb', line 106

def serializable_hash(options = nil)
  options = options.try(:dup) || {}
  options[:except] = Array(options[:except]).dup

  if options[:force_except]
    options[:except].concat Array(options[:force_except])
  else
    options[:except].concat UNSAFE_ATTRIBUTES_FOR_SERIALIZATION
  end

  super(options)
end

#strip_whitespaceObject (protected)



211
212
213
# File 'lib/devise/models/authenticatable.rb', line 211

def strip_whitespace
  self.class.strip_whitespace_keys.each { |k| apply_to_attribute_or_variable(k, :strip) }
end

#unauthenticated_messageObject



86
87
88
# File 'lib/devise/models/authenticatable.rb', line 86

def unauthenticated_message
  :invalid
end

#valid_for_authentication?Boolean

Check if the current object is valid for authentication. This method and find_for_authentication are the methods used in a Warden::Strategy to check if a model should be signed in or not.

However, you should not overwrite this method, you should overwrite active_for_authentication? and inactive_message instead.

Returns:

  • (Boolean)


82
83
84
# File 'lib/devise/models/authenticatable.rb', line 82

def valid_for_authentication?
  block_given? ? yield : true
end