Skip to content

Commit

Permalink
Create after_sign_in_path_for and after_sign_out_path_for hooks and s…
Browse files Browse the repository at this point in the history
…ign_in_and_redirect and sign_out_and_redirect helpers.
  • Loading branch information
josevalim committed Nov 19, 2009
1 parent 977b7f2 commit d445b4b
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 51 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.rdoc
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
* enhancements
* [#37] Create after_sign_in_path_for and after_sign_out_path_for hooks to be
overwriten in ApplicationController
* Create sign_in_and_redirect and sign_out_and_redirect helpers

== 0.5.3

* bug fix
Expand Down
28 changes: 6 additions & 22 deletions README.rdoc
Original file line number Diff line number Diff line change
Expand Up @@ -103,33 +103,15 @@ The next step after setting up your model is to configure your routes for devise

map.devise_for :users

This is going to look inside you User model and create the needed routes:
This is going to look inside you User model and create a set of needed routes (you can see them by running `rake routes`).

# Session routes for Authenticatable (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 run the routes rake task to verify what routes are being created by devise.

There are also some options available for configuring your routes, as :class_name (to set the class for that route), :as and :path_names, where the last two have the same meaning as in routes. The available :path_names are:
There are also some options available for configuring your routes, as :class_name (to set the class for that route), :as and :path_names, where the last two have the same meaning as in common routes. The available :path_names are:

map.devise_for :users, :as => "usuarios", :path_names => { :sign_in => 'login', :sign_out => 'logout', :password => 'secret', :confirmation => 'verification' }

Be sure to check devise_for documentation for detailed description.

== Controller filters
== Controller filters and helpers

Devise is gonna create some helpers to use inside your controllers and views. To setup a controller that needs user authentication, just add this before_filter:

Expand All @@ -151,7 +133,9 @@ After signing in a user, confirming it's account or updating it's password, devi

map.root :controller => 'home'

You also need to setup default url options for the mailer, if you are using confirmable or recoverable. Here's is the configuration for development:
You can also overwrite after_sign_in_path_for and after_sign_out_path_for to customize better your redirect hooks.

Finally, if you are using confirmable or recoverable, you also need to setup default url options for the mailer. Here's is the configuration for development:

DeviseMailer.sender = "no-reply@yourapp.com"
config.action_mailer.default_url_options = { :host => 'localhost:3000' }
Expand Down
3 changes: 1 addition & 2 deletions app/controllers/confirmations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,8 @@ def show
self.resource = resource_class.confirm!(:confirmation_token => params[:confirmation_token])

if resource.errors.empty?
sign_in(resource_name, resource)
set_flash_message :success, :confirmed
redirect_to home_or_root_path
sign_in_and_redirect(resource_name, resource)
else
render :new
end
Expand Down
3 changes: 1 addition & 2 deletions app/controllers/passwords_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ def update
self.resource = resource_class.reset_password!(params[resource_name])

if resource.errors.empty?
sign_in(resource_name, resource)
set_flash_message :success, :updated
redirect_to home_or_root_path
sign_in_and_redirect(resource_name, resource)
else
render :edit
end
Expand Down
5 changes: 2 additions & 3 deletions app/controllers/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ def new
def create
if authenticate(resource_name)
set_flash_message :success, :signed_in
redirect_back_or_to home_or_root_path
sign_in_and_redirect(resource_name)
else
set_now_flash_message :failure, warden.message || :invalid
build_resource
Expand All @@ -26,8 +26,7 @@ def create
# GET /resource/sign_out
def destroy
set_flash_message :success, :signed_out if signed_in?(resource_name)
sign_out(resource_name)
redirect_to root_path
sign_out_and_redirect(resource_name)
end

end
47 changes: 47 additions & 0 deletions lib/devise/controllers/filters.rb
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,53 @@ def stored_location_for(resource_or_scope)
session.delete(:"#{scope}.return_to")
end

# The default url to be used after signing in. This is used by all Devise
# controllers and you can overwrite it in your ApplicationController to
# provide a custom hook for a custom resource.
#
# By default, it first tries to find a resource_root_path, otherwise it
# uses the root path. For a user scope, you can define the default url in
# the following way:
#
# map.user_root '/users', :controller => 'users' # creates user_root_path
#
# map.resources :users do |users|
# users.root # creates user_root_path
# end
#
# If none of these are defined, root_path is used.
def after_sign_in_path_for(resource_or_scope)
scope = Devise::Mapping.find_scope!(resource_or_scope)
home_path = :"#{scope}_root_path"
respond_to?(home_path, true) ? send(home_path) : root_path
end

# The default to be used after signing out. This is used by all Devise
# controllers and you can overwrite it in your ApplicationController to
# provide a custom hook for a custom resource.
#
# By default is the root_path.
def after_sign_out_path_for(resource_or_scope)
root_path
end

# Sign in an user and tries to redirect first to the stored location and
# then to the url specified by after_sign_in_path_for.
#
# If just a symbol is given, consider that the user was already signed in
# through other means and just perform the redirection.
def sign_in_and_redirect(*args)
sign_in(*args) unless args.one? && args.first.is_a?(Symbol)
redirect_to stored_location_for(args.first) || after_sign_in_path_for(args.first)
end

# Sign out an user and tries to redirect to the url specified by
# after_sign_out_path_for.
def sign_out_and_redirect(resource_or_scope)
sign_out(resource_or_scope)
redirect_to after_sign_out_path_for(resource_or_scope)
end

# 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
Expand Down
23 changes: 1 addition & 22 deletions lib/devise/controllers/helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,27 +44,6 @@ def devise_controller?

protected

# Redirects to stored uri before signing in or the default path and clear
# return to.
def redirect_back_or_to(default)
redirect_to(stored_location_for(resource_name) || default)
end

# Checks for the existence of the resource root path. If it exists,
# returns it, otherwise returns the default root_path.
# Used after authenticating a user, confirming it's account or updating
# it's password, so we are able to redirect to scoped root paths.
# Examples (for a user scope):
# map.user_root '/users', :controller => 'users' # creates user_root_path
#
# map.namespace :users do |users|
# users.root # creates user_root_path
# end
def home_or_root_path
home_path = :"#{resource_name}_root_path"
respond_to?(home_path, true) ? send(home_path) : root_path
end

# Checks whether it's a devise mapped resource or not.
def is_devise_resource? #:nodoc:
raise ActionController::UnknownAction unless devise_mapping && devise_mapping.allows?(controller_name)
Expand All @@ -88,7 +67,7 @@ def build_resource
# Example:
# before_filter :require_no_authentication, :only => :new
def require_no_authentication
redirect_to home_or_root_path if warden.authenticated?(resource_name)
redirect_to after_sign_in_path_for(resource_name) if warden.authenticated?(resource_name)
end

# Sets the flash message with :key, using I18n. By default you are able
Expand Down
36 changes: 36 additions & 0 deletions test/controllers/filters_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,42 @@ def setup
assert_nil @controller.session[:"user.return_to"]
end

test 'after sign in path defaults to root path if none by was specified for the given scope' do
assert_equal root_path, @controller.after_sign_in_path_for(:user)
end

test 'after sign in path defaults to the scoped root path' do
assert_equal admin_root_path, @controller.after_sign_in_path_for(:admin)
end

test 'after sign out path defaults to the root path' do
assert_equal root_path, @controller.after_sign_out_path_for(:admin)
assert_equal root_path, @controller.after_sign_out_path_for(:user)
end

test 'sign in and redirect uses the stored location' do
user = User.new
@controller.session[:"user.return_to"] = "/foo.bar"
@mock_warden.expects(:set_user).with(user, :scope => :user).returns(true)
@controller.expects(:redirect_to).with("/foo.bar")
@controller.sign_in_and_redirect(user)
end

test 'sign in and redirect uses the configured after sign in path' do
admin = Admin.new
@mock_warden.expects(:set_user).with(admin, :scope => :admin).returns(true)
@controller.expects(:redirect_to).with(admin_root_path)
@controller.sign_in_and_redirect(admin)
end

test 'sign out and redirect uses the configured after sign out path' do
@mock_warden.expects(:user).with(:admin).returns(true)
@mock_warden.expects(:logout).with(:admin).returns(true)
@controller.expects(:redirect_to).with(admin_root_path)
@controller.instance_eval "def after_sign_out_path_for(resource); admin_root_path; end"
@controller.sign_out_and_redirect(:admin)
end

test 'is not a devise controller' do
assert_not @controller.devise_controller?
end
Expand Down

0 comments on commit d445b4b

Please sign in to comment.