Rememberable manages generating and clearing token for remember the user from a saved cookie. Rememberable also has utility methods for dealing with serializing the user into the cookie and back from the cookie, trying to lookup the record based on the saved information. You probably wouldn't use rememberable methods directly, they are used mostly internally for handling the remember token.
Rememberable adds the following options in devise_for:
* +remember_for+: the time you want the user will be remembered without asking for credentials. After this time the user will be blocked and will have to enter their credentials again. This configuration is also used to calculate the expires time for the cookie created to remember the user. By default remember_for is 2.weeks. * +extend_remember_period+: if true, extends the user's remember period when remembered via cookie. False by default. * +rememberable_options+: configuration options passed to the created cookie.
User.find(1).remember_me! # regenerating the token User.find(1).forget_me! # clearing the token # generating info to put into cookies User.serialize_into_cookie(user) # lookup the user based on the incoming cookie information User.serialize_from_cookie(cookie_string)
# File lib/devise/models/rememberable.rb, line 44 def self.required_fields(klass) [:remember_created_at] end
A callback initiated after successfully being remembered. This can be used to insert your own logic that is only run after the user is remembered.
Example:
def after_remembered self.update_attribute(:invite_code, nil) end
# File lib/devise/models/rememberable.rb, line 101 def after_remembered end
If the record is persisted, remove the remember token (but only if it exists), and save the record without validations.
# File lib/devise/models/rememberable.rb, line 58 def forget_me! return unless persisted? self.remember_token = nil if respond_to?(:remember_token) self.remember_created_at = nil if self.class.expire_all_remember_me_on_sign_out save(validate: false) end
Remember token should be expired if expiration time not overpass now.
# File lib/devise/models/rememberable.rb, line 66 def remember_expired? remember_created_at.nil? end
# File lib/devise/models/rememberable.rb, line 70 def remember_expires_at self.class.remember_for.from_now end
TODO: We were used to receive a extend period argument but we no longer do. Remove this for Devise 4.0.
# File lib/devise/models/rememberable.rb, line 50 def remember_me!(*) self.remember_token = self.class.remember_token if respond_to?(:remember_token) self.remember_created_at ||= Time.now.utc save(validate: false) if self.changed? end
# File lib/devise/models/rememberable.rb, line 104 def remember_me?(token, generated_at) # TODO: Normalize the JSON type coercion along with the Timeoutable hook # in a single place https://github.com/plataformatec/devise/blob/ffe9d6d406e79108cf32a2c6a1d0b3828849c40b/lib/devise/hooks/timeoutable.rb#L14-L18 if generated_at.is_a?(String) generated_at = time_from_json(generated_at) end # The token is only valid if: # 1. we have a date # 2. the current time does not pass the expiry period # 3. the record has a remember_created_at date # 4. the token date is bigger than the remember_created_at # 5. the token matches generated_at.is_a?(Time) && (self.class.remember_for.ago < generated_at) && (generated_at > (remember_created_at || Time.now).utc) && Devise.secure_compare(rememberable_value, token) end
# File lib/devise/models/rememberable.rb, line 87 def rememberable_options self.class.rememberable_options end
# File lib/devise/models/rememberable.rb, line 74 def rememberable_value if respond_to?(:remember_token) remember_token elsif respond_to?(:authenticatable_salt) && (salt = authenticatable_salt.presence) salt else raise "authenticable_salt returned nil for the #{self.class.name} model. " "In order to use rememberable, you must ensure a password is always set " "or have a remember_token column in your model or implement your own " "rememberable_value in the model with custom logic." end end
# File lib/devise/models/rememberable.rb, line 125 def time_from_json(value) if value =~ /\A\d+\.\d+\Z/ Time.at(value.to_f) else Time.parse(value) rescue nil end end