Permalink
Browse files

Create after_sign_in_path_for and after_sign_out_path_for hooks and s…

…ign_in_and_redirect and sign_out_and_redirect helpers.
  • Loading branch information...
1 parent 977b7f2 commit d445b4beb99c8c9eff885bebe5933a91e3b9ee78 @josevalim josevalim committed Nov 19, 2009
View
@@ -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
View
@@ -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:
@@ -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' }
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)
@@ -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
@@ -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

0 comments on commit d445b4b

Please sign in to comment.