module Authlogic module ActsAsAuthentic # This provides a handy token that is "perishable". Meaning the token is only good for a certain amount of time. This is perfect for # resetting password, confirming accounts, etc. Typically during these actions you send them this token in via their email. Once they # use the token and do what they need to do, that token should expire. Don't worry about maintaining this, changing it, or expiring it # yourself. Authlogic does all of this for you. See the sub modules for all of the tools Authlogic provides to you. module PerishableToken def self.included(klass) klass.class_eval do extend Config add_acts_as_authentic_module(Methods) end end # Change how the perishable token works. module Config # When using the find_using_perishable_token method the token can expire. If the token is expired, no # record will be returned. Use this option to specify how long the token is valid for. # # * Default: 10.minutes # * Accepts: Fixnum def perishable_token_valid_for(value = nil) rw_config(:perishable_token_valid_for, (!value.nil? && value.to_i) || value, 10.minutes.to_i) end alias_method :perishable_token_valid_for=, :perishable_token_valid_for # Authlogic tries to expire and change the perishable token as much as possible, without comprising # it's purpose. This is for security reasons. If you want to manage it yourself, you can stop # Authlogic from getting your in way by setting this to true. # # * Default: false # * Accepts: Boolean def disable_perishable_token_maintenance(value = nil) rw_config(:disable_perishable_token_maintenance, value, false) end alias_method :disable_perishable_token_maintenance=, :disable_perishable_token_maintenance end # All methods relating to the perishable token. module Methods def self.included(klass) return if !klass.column_names.include?("perishable_token") klass.class_eval do extend ClassMethods include InstanceMethods validates_uniqueness_of :perishable_token, :if => :perishable_token_changed? before_save :reset_perishable_token, :unless => :disable_perishable_token_maintenance? end end # Class level methods for the perishable token module ClassMethods # Use this methdo to find a record with a perishable token. This method does 2 things for you: # # 1. It ignores blank tokens # 2. It enforces the perishable_token_valid_for configuration option. # # If you want to use a different timeout value, just pass it as the second parameter: # # User.find_using_perishable_token(token, 1.hour) def find_using_perishable_token(token, age = self.perishable_token_valid_for) return if token.blank? age = age.to_i conditions_sql = "perishable_token = ?" conditions_subs = [token] if column_names.include?("updated_at") && age > 0 conditions_sql += " and updated_at > ?" conditions_subs << age.seconds.ago end find(:first, :conditions => [conditions_sql, *conditions_subs]) end # This method will raise ActiveRecord::NotFound if no record is found. def find_using_perishable_token!(token, age = perishable_token_valid_for) find_using_perishable_token(token, age) || raise(StandardError) # || raise(ActiveRecord::RecordNotFound) end end # Instance level methods for the perishable token. module InstanceMethods # Resets the perishable token to a random friendly token. def reset_perishable_token self.perishable_token = Random.friendly_token end # Same as reset_perishable_token, but then saves the record afterwards. def reset_perishable_token! reset_perishable_token save_without_session_maintenance(false) end # A convenience method based on the disable_perishable_token_maintenance configuration option. def disable_perishable_token_maintenance? self.class.disable_perishable_token_maintenance == true end end end end end end