Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Better documentation.

  • Loading branch information...
commit b21b6291b090cc523ec2b306f9a4a4c9f22a605f 1 parent a5cb147
Carlos Antonio da Silva carlosantoniodasilva authored
6 README.rdoc
View
@@ -97,10 +97,14 @@ There are also some options available for configuring your routes:
map.devise_for :users, :class_name => 'Account'
-* :as => Let's you setup the path name that will be used, as rails routes does. The following route configuration would setup your route as /accounts/session and so on:
+* :as => allows you to setup path name that will be used, as rails routes does. The following route configuration would setup your route as /accounts instead of /users:
map.devise_for :users, :as => 'accounts'
+* :singular => setup the name used to create named routes. By default, for a :users key, it is going to be the singularized version, :user. To configure a named route like account_session_path instead of user_session_path just do:
+
+ map.devise_for :users, :singular => :user
+
* :path_names => configure different path names to overwrite defaults :sign_in, :sign_out, :password and :confirmation.
map.devise_for :users, :path_names => { :sign_in => 'login', :sign_out => 'logout', :password => 'secret', :confirmation => 'verification' }
9 app/controllers/confirmations_controller.rb
View
@@ -1,13 +1,11 @@
class ConfirmationsController < ApplicationController
before_filter :is_devise_resource?
- # GET /confirmation/new
- #
+ # GET /resource/confirmation/new
def new
end
- # POST /confirmation
- #
+ # POST /resource/confirmation
def create
self.resource = resource_class.send_confirmation_instructions(params[resource_name])
@@ -19,8 +17,7 @@ def create
end
end
- # GET /confirmation?perishable_token=abcdef
- #
+ # GET /resource/confirmation?perishable_token=abcdef
def show
self.resource = resource_class.confirm!(:perishable_token => params[:perishable_token])
13 app/controllers/passwords_controller.rb
View
@@ -1,13 +1,11 @@
class PasswordsController < ApplicationController
before_filter :is_devise_resource?, :require_no_authentication
- # GET /password/new
- #
+ # GET /resource/password/new
def new
end
- # POST /password
- #
+ # POST /resource/password
def create
self.resource = resource_class.send_reset_password_instructions(params[resource_name])
@@ -19,17 +17,16 @@ def create
end
end
- # GET /password/edit?perishable_token=abcdef
- #
+ # GET /resource/password/edit?perishable_token=abcdef
def edit
self.resource = resource_class.new
resource.perishable_token = params[:perishable_token]
end
- # PUT /password
- #
+ # PUT /resource/password
def update
self.resource = resource_class.reset_password!(params[resource_name])
+
if resource.errors.empty?
set_flash_message :success, :updated
redirect_to new_session_path(resource_name)
7 app/controllers/sessions_controller.rb
View
@@ -2,12 +2,12 @@ class SessionsController < ApplicationController
before_filter :is_devise_resource?
before_filter :require_no_authentication, :only => [ :new, :create ]
- # GET /session/sign_in
+ # GET /resource/sign_in
def new
unauthenticated! if params[:unauthenticated]
end
- # POST /session/sign_in
+ # POST /resource/sign_in
def create
if sign_in(resource_name)
set_flash_message :success, :signed_in
@@ -18,8 +18,7 @@ def create
end
end
- # GET /session/sign_out
- # DELETE /session/sign_out
+ # GET /resource/sign_out
def destroy
set_flash_message :success, :signed_out if signed_in?(resource_name)
sign_out(resource_name)
7 app/models/notifier.rb
View
@@ -1,16 +1,14 @@
class Notifier < ::ActionMailer::Base
cattr_accessor :sender
- # Deliver confirmation instructions when the user is created or confirmation
- # is manually requested
- #
+ # Deliver confirmation instructions when the user is created or its email is
+ # updated, and also when confirmation is manually requested
def confirmation_instructions(record)
subject translate(:confirmation_instructions, :default => 'Confirmation instructions')
setup_mail(record)
end
# Deliver reset password instructions when manually requested
- #
def reset_password_instructions(record)
subject translate(:reset_password_instructions, :default => 'Reset password instructions')
setup_mail(record)
@@ -18,6 +16,7 @@ def reset_password_instructions(record)
private
+ # Configure default email options
def setup_mail(record)
from self.class.sender
recipients record.email
1  lib/devise.rb
View
@@ -12,7 +12,6 @@
# Ensure to include Devise modules only after Rails initialization.
# This way application should have already defined Devise mappings and we are
# able to create default filters.
-#
Rails.configuration.after_initialize do
ActiveRecord::Base.extend Devise::ActiveRecord
end
5 lib/devise/active_record.rb
View
@@ -1,6 +1,6 @@
module Devise
module ActiveRecord
- # Shortcut method for including all devise modules inside your User class
+ # Shortcut method for including all devise modules inside your model
#
# Examples:
#
@@ -21,7 +21,6 @@ module ActiveRecord
#
# # shortcut to include all modules (same as above)
# devise :all
- #
def devise(*options)
options = [:confirmable, :recoverable, :validatable] if options.include?(:all)
options |= [:authenticable]
@@ -33,6 +32,8 @@ def devise(*options)
end
end
+ # Stores all modules included inside the model, so we are able to verify
+ # which routes are needed.
def devise_modules
@devise_modules ||= []
end
20 lib/devise/controllers/filters.rb
View
@@ -35,24 +35,28 @@ def sign_out(scope, *args)
warden.logout(scope, *args)
end
- # Define authentication filters based on mappings. These filters should be
- # used inside the controllers as before_filters, so you can control the
- # scope of the user who should be signed in to access that specific
- # controller/action.
- #
+ # Define authentication filters and accessor helpers based on mappings.
+ # These filters should be used inside the controllers as before_filters,
+ # so you can control the scope of the user who should be signed in to
+ # access that specific controller/action.
# Example:
#
# Maps:
- # Devise.map :user, :for => [:authenticable]
- # Devise.map :admin, :for => [:authenticable]
+ # User => :authenticable
+ # Admin => :authenticable
#
# Generated Filters:
# sign_in_user!
# sign_in_admin!
- #
# Use:
# before_filter :sign_in_user! # Tell devise to use :user map
# before_filter :sign_in_admin! # Tell devise to use :admin map
+ #
+ # Generated helpers:
+ # user_signed_in? # Checks whether there is an user signed in or not
+ # admin_signed_in? # Checks whether there is an admin signed in or not
+ # current_user # Current signed in user
+ # current_admin # Currend signed in admin
Devise.mappings.each_key do |mapping|
class_eval <<-METHODS, __FILE__, __LINE__
def sign_in_#{mapping}!
20 lib/devise/controllers/helpers.rb
View
@@ -8,28 +8,48 @@ def self.included(base)
end
end
+ # Gets the actual resource stored in the instance variable
def resource
instance_variable_get(:"@#{resource_name}")
end
+ # Proxy to devise map name
def resource_name
devise_mapping.name
end
+ # Proxy to devise map class
def resource_class
devise_mapping.to
end
protected
+ # Attempt to find the mapped route for devise based on request path
def devise_mapping
@devise_mapping ||= Devise.find_mapping_by_path(request.path)
end
+ # Sets the resource creating an instance variable
def resource=(new_resource)
instance_variable_set(:"@#{resource_name}", new_resource)
end
+ # Sets the flash message with :key, using I18n. By default you are able
+ # to setup your messages using specific resource scope, and if no one is
+ # found we look to default scope.
+ # Example (i18n locale file):
+ #
+ # en:
+ # devise:
+ # passwords:
+ # #default_scope_messages - only if resource_scope is not found
+ # user:
+ # passwords:
+ # #resource_scope_messages
+ #
+ # Please refer to README or en.yml locale file to check what messages are
+ # available.
def set_flash_message(key, kind)
flash[key] = I18n.t(:"#{resource_name}.#{kind}",
:scope => [:devise, controller_name.to_sym], :default => kind)
15 lib/devise/controllers/url_helpers.rb
View
@@ -2,6 +2,21 @@ module Devise
module Controllers
module UrlHelpers
+ # Create url helpers to be used with resource/scope configuration. Acts as
+ # proxies to the generated routes created by devise.
+ # Resource param can be a string or symbol, a class, or an instance object.
+ # Example using a :user resource:
+ #
+ # new_session_path(:user) => new_user_session_path
+ # session_path(:user) => user_session_path
+ # destroy_session_path(:user) => destroy_user_session_path
+ #
+ # new_password_path(:user) => new_user_password_path
+ # password_path(:user) => user_password_path
+ # edit_password_path(:user) => edit_user_password_path
+ #
+ # new_confirmation_path(:user) => new_user_confirmation_path
+ # confirmation_path(:user) => user_confirmation_path
[:session, :password, :confirmation].each do |module_name|
[:path, :url].each do |path_or_url|
actions = [ nil, :new_ ]
27 lib/devise/mapping.rb
View
@@ -1,10 +1,14 @@
module Devise
+ # Maps controller names to devise modules
CONTROLLERS = {
:sessions => :authenticable,
:passwords => :recoverable,
:confirmations => :confirmable
}.freeze
+ # Responsible for handling devise mappings and routes configuration. Each
+ # resource configured by devise_for in routes is actually creating a mapping
+ # object. Please refer to devise_for in routes for more info.
class Mapping
attr_reader :name, :as, :path_names
@@ -13,9 +17,7 @@ def initialize(name, options)
@klass = (options[:class_name] || name.to_s.classify).to_s
@name = (options[:singular] || name.to_s.singularize).to_sym
@path_names = options[:path_names] || {}
- [:sign_in, :sign_out, :password, :confirmation].each do |path_name|
- @path_names[path_name] ||= path_name.to_s
- end
+
end
# Return modules for the mapping.
@@ -36,6 +38,12 @@ def allows?(controller)
self.for.include?(CONTROLLERS[controller.to_sym])
end
+ # Create magic predicates for verifying what module is activated by this map.
+ # Example:
+ #
+ # def confirmable?
+ # self.for.include?(:confirmable)
+ # end
CONTROLLERS.values.each do |m|
class_eval <<-METHOD, __FILE__, __LINE__
def #{m}?
@@ -43,11 +51,24 @@ def #{m}?
end
METHOD
end
+
+ private
+
+ # Configure default path names, allowing the user overwrite defaults by
+ # passing a hash in :path_names.
+ def setup_path_names
+ [:sign_in, :sign_out, :password, :confirmation].each do |path_name|
+ @path_names[path_name] ||= path_name.to_s
+ end
+ end
end
mattr_accessor :mappings
self.mappings = {}
+ # Loop through all mappings looking for a map that matches with the requested
+ # path (ie /users/sign_in). The important part here is the key :users. If no
+ # map is found just returns nil.
def self.find_mapping_by_path(path)
route = path.split("/")[1]
return nil unless route
6 lib/devise/models/authenticable.rb
View
@@ -17,7 +17,6 @@ module Models
#
# User.authenticate('email@test.com', 'password123') # returns authenticated user or nil
# User.find(1).valid_password?('password123') # returns true/false
- #
module Authenticable
mattr_accessor :pepper, :stretches
@@ -44,7 +43,6 @@ def password=(new_password)
end
# Verifies whether an incoming_password (ie from login) is the user password
- #
def valid_password?(incoming_password)
password_digest(incoming_password) == encrypted_password
end
@@ -53,7 +51,6 @@ def valid_password?(incoming_password)
# Gererates a default password digest based on salt, pepper and the
# incoming password
- #
def password_digest(password_to_digest)
digest = pepper
stretches.times { digest = secure_digest(password_salt, digest, password_to_digest, pepper) }
@@ -63,13 +60,11 @@ def password_digest(password_to_digest)
# Generate a SHA1 digest joining args. Generated token is something like
#
# --arg1--arg2--arg3--argN--
- #
def secure_digest(*tokens)
::Digest::SHA1.hexdigest('--' << tokens.flatten.join('--') << '--')
end
# Generate a friendly string randomically to be used as token
- #
def friendly_token
ActiveSupport::SecureRandom.base64(15).tr('+/=', '-_ ').strip.delete("\n")
end
@@ -79,7 +74,6 @@ module ClassMethods
# Authenticate a user based on email and password. Returns the
# authenticated user if it's valid or nil.
# Attributes are :email and :password
- #
def authenticate(attributes={})
authenticable = self.find_by_email(attributes[:email])
authenticable if authenticable.try(:valid_password?, attributes[:password])
13 lib/devise/models/confirmable.rb
View
@@ -9,16 +9,12 @@ module Models
# Whenever the user update it's email, his account is automatically unconfirmed,
# it means it won't be able to sign in again without confirming the account
# again through the email that was sent.
- # Confirmable also hooks into authenticate, to verify if the account is
- # confirmed or not before authenticating the user.
# Examples:
#
- # User.authenticate('email@test.com', 'password123') # true if it's confirmed, otherwise false
# User.find(1).confirm! # returns true unless it's already confirmed
# User.find(1).confirmed? # true/false
# User.find(1).send_confirmation_instructions # manually send instructions
# User.find(1).reset_confirmation! # reset confirmation status and send instructions
- #
module Confirmable
def self.included(base)
@@ -32,7 +28,6 @@ def self.included(base)
# Confirm a user by setting it's confirmed_at to actual time. If the user
# is already confirmed, add en error to email field
- #
def confirm!
unless_confirmed do
clear_perishable_token
@@ -41,13 +36,11 @@ def confirm!
end
# Verifies whether a user is confirmed or not
- #
def confirmed?
!new_record? && confirmed_at?
end
# Send confirmation instructions by email
- #
def send_confirmation_instructions
::Notifier.deliver_confirmation_instructions(self)
end
@@ -55,7 +48,6 @@ def send_confirmation_instructions
# Remove confirmation date and send confirmation instructions, to ensure
# after sending these instructions the user won't be able to sign in without
# confirming it's account
- #
def reset_confirmation!
unless_confirmed do
reset_confirmation
@@ -68,7 +60,6 @@ def reset_confirmation!
# Remove confirmation date from the user, ensuring after a user update it's
# email, it won't be able to sign in without confirming it.
- #
def reset_confirmation
reset_perishable_token
self.confirmed_at = nil
@@ -76,7 +67,6 @@ def reset_confirmation
# Checks whether the record is confirmed or not, yielding to the block if
# it's already confirmed, otherwise adds an error to email.
- #
def unless_confirmed
unless confirmed?
yield
@@ -87,11 +77,11 @@ def unless_confirmed
end
module ClassMethods
+
# Attempt to find a user by it's email. If a record is found, send new
# confirmation instructions to it. If not user is found, returns a new user
# with an email not found error.
# Options must contain the user email
- #
def send_confirmation_instructions(attributes={})
confirmable = find_or_initialize_with_error_by_email(attributes[:email])
confirmable.reset_confirmation! unless confirmable.new_record?
@@ -102,7 +92,6 @@ def send_confirmation_instructions(attributes={})
# If no user is found, returns a new user
# If the user is already confirmed, create an error for the user
# Options must have the perishable_token
- #
def confirm!(attributes={})
confirmable = find_or_initialize_with_error_by_perishable_token(attributes[:perishable_token])
confirmable.confirm! unless confirmable.new_record?
6 lib/devise/models/perishable.rb
View
@@ -15,7 +15,6 @@ module Models
# # only create a new token, without saving the record
# user = User.find(1)
# user.reset_perishable_token
- #
module Perishable
def self.included(base)
@@ -25,17 +24,16 @@ def self.included(base)
end
# Generates a new random token for confirmation, based on actual Time and salt
- #
def reset_perishable_token
self.perishable_token = friendly_token
end
# Resets the perishable token with and save the record without validating
- #
def reset_perishable_token!
reset_perishable_token && save(false)
end
+ # Removes perishable token
def clear_perishable_token
self.perishable_token = nil
end
@@ -44,7 +42,6 @@ module ClassMethods
# Attempt to find a user by and incoming perishable_token. If no user is
# found, initialize a new one and adds an :invalid error to perishable_token
- #
def find_or_initialize_with_error_by_perishable_token(perishable_token)
perishable = find_or_initialize_by_perishable_token(perishable_token)
if perishable.new_record?
@@ -55,7 +52,6 @@ def find_or_initialize_with_error_by_perishable_token(perishable_token)
# Attempt to find a user by it's email. If not user is found, returns a
# new user with an email not found error.
- #
def find_or_initialize_with_error_by_email(email)
perishable = find_or_initialize_by_email(email)
if perishable.new_record?
6 lib/devise/models/recoverable.rb
View
@@ -11,7 +11,6 @@ module Models
# user.reset_password('password123', 'password123')
# # creates a new token and send it with instructions about how to reset the password
# User.find(1).send_reset_password_instructions
- #
module Recoverable
def self.included(base)
base.class_eval do
@@ -20,7 +19,6 @@ def self.included(base)
end
# Update password
- #
def reset_password(new_password, new_password_confirmation)
self.password = new_password
self.password_confirmation = new_password_confirmation
@@ -28,7 +26,6 @@ def reset_password(new_password, new_password_confirmation)
# Update password saving the record and clearing token. Returns true if
# the passwords are valid and the record was saved, false otherwise.
- #
def reset_password!(new_password, new_password_confirmation)
reset_password(new_password, new_password_confirmation)
clear_perishable_token
@@ -36,7 +33,6 @@ def reset_password!(new_password, new_password_confirmation)
end
# Resets perishable token and send reset password instructions by email
- #
def send_reset_password_instructions
reset_perishable_token!
::Notifier.deliver_reset_password_instructions(self)
@@ -48,7 +44,6 @@ module ClassMethods
# password instructions to it. If not user is found, returns a new user
# with an email not found error.
# Attributes must contain the user email
- #
def send_reset_password_instructions(attributes={})
recoverable = find_or_initialize_with_error_by_email(attributes[:email])
recoverable.send_reset_password_instructions unless recoverable.new_record?
@@ -60,7 +55,6 @@ def send_reset_password_instructions(attributes={})
# record. If not user is found, returns a new user containing an error
# in perishable_token attribute.
# Attributes must contain perishable_token, password and confirmation
- #
def reset_password!(attributes={})
recoverable = find_or_initialize_with_error_by_perishable_token(attributes[:perishable_token])
recoverable.reset_password!(attributes[:password], attributes[:password_confirmation]) unless recoverable.new_record?
3  lib/devise/models/validatable.rb
View
@@ -5,11 +5,9 @@ module Models
# It's optional, given you may want to create the validations by yourself.
# Automatically validate if the email is present, unique and it's format is
# valid. Also tests presence of password, confirmation and length
- #
module Validatable
# Email regex used to validate email formats. Retrieved from authlogic.
- #
EMAIL_REGEX = /\A[\w\.%\+\-]+@(?:[A-Z0-9\-]+\.)+(?:[A-Z]{2,4}|museum|travel)\z/i
def self.included(base)
@@ -30,7 +28,6 @@ def self.included(base)
# Checks whether a password is needed or not. For validations only.
# Passwords are always required if it's a new record, or if the password
# or confirmation are being set somewhere.
- #
def password_required?
new_record? || !password.nil? || !password_confirmation.nil?
end
50 lib/devise/routes.rb
View
@@ -1,9 +1,9 @@
module ActionController::Routing
class RouteSet #:nodoc:
- # Alias to include Devise modules after only loading routes, because we need
- # devise_for mappings already done to create magic filters and helpers.
- #
+ # Ensure Devise modules are included only after loading routes, because we
+ # need devise_for mappings already declared to create magic filters and
+ # helpers.
def load_routes_with_devise!
load_routes_without_devise!
@@ -16,8 +16,50 @@ def load_routes_with_devise!
alias_method_chain :load_routes!, :devise
class Mapper #:doc:
- # Includes devise_for map for routes.
+ # Includes devise_for method for routes. This method is responsible to
+ # generate all needed routes for devise, based on what modules you have
+ # defined in your model.
+ # Examples: Let's say you have an User model configured to use
+ # authenticable, confirmable and recoverable modules. After creating this
+ # inside your routes:
#
+ # map.devise_for :users
+ #
+ # this method is going to look inside your User model and create the
+ # needed routes:
+ #
+ # # Session routes for Authenticable (default)
+ # new_user_session GET /users/sign_in {:controller=>"sessions", :action=>"new"}
+ # user_session POST /users/sign_in {:controller=>"sessions", :action=>"create"}
+ # destroy_user_session GET /users/sign_out {:controller=>"sessions", :action=>"destroy"}
+ #
+ # # Password routes for Recoverable, if User model has :recoverable configured
+ # new_user_password GET /users/password/new(.:format) {:controller=>"passwords", :action=>"new"}
+ # edit_user_password GET /users/password/edit(.:format) {:controller=>"passwords", :action=>"edit"}
+ # user_password PUT /users/password(.:format) {:controller=>"passwords", :action=>"update"}
+ # POST /users/password(.:format) {:controller=>"passwords", :action=>"create"}
+ #
+ # # Confirmation routes for Confirmable, if User model has :confirmable configured
+ # new_user_confirmation GET /users/confirmation/new(.:format) {:controller=>"confirmations", :action=>"new"}
+ # user_confirmation GET /users/confirmation(.:format) {:controller=>"confirmations", :action=>"show"}
+ # POST /users/confirmation(.:format) {:controller=>"confirmations", :action=>"create"}
+ #
+ # You can configure your routes with some options:
+ # * :class_name => setup a different class to be looked up by devise, if it cannot be correctly find by the route name.
+ #
+ # map.devise_for :users, :class_name => 'Account'
+ #
+ # * :as => allows you to setup path name that will be used, as rails routes does. The following route configuration would setup your route as /accounts instead of /users:
+ #
+ # map.devise_for :users, :as => 'accounts'
+ #
+ # * :singular => setup the name used to create named routes. By default, for a :users key, it is going to be the singularized version, :user. To configure a named route like account_session_path instead of user_session_path just do:
+ #
+ # map.devise_for :users, :singular => :user
+ #
+ # * :path_names => configure different path names to overwrite defaults :sign_in, :sign_out, :password and :confirmation.
+ #
+ # map.devise_for :users, :path_names => { :sign_in => 'login', :sign_out => 'logout', :password => 'secret', :confirmation => 'verification' }
def devise_for(*resources)
options = resources.extract_options!
Please sign in to comment.
Something went wrong with that request. Please try again.