diff --git a/lib/devise.rb b/lib/devise.rb index 3455cb58..289fa03a 100644 --- a/lib/devise.rb +++ b/lib/devise.rb @@ -21,6 +21,7 @@ module Devise autoload :Rememberable, 'devise/controllers/rememberable' autoload :ScopedViews, 'devise/controllers/scoped_views' autoload :SignInOut, 'devise/controllers/sign_in_out' + autoload :StoreLocation, 'devise/controllers/store_location' autoload :UrlHelpers, 'devise/controllers/url_helpers' end diff --git a/lib/devise/controllers/helpers.rb b/lib/devise/controllers/helpers.rb index 842a8d09..066e2e39 100644 --- a/lib/devise/controllers/helpers.rb +++ b/lib/devise/controllers/helpers.rb @@ -4,6 +4,7 @@ module Devise module Helpers extend ActiveSupport::Concern include Devise::Controllers::SignInOut + include Devise::Controllers::StoreLocation included do helper_method :warden, :signed_in?, :devise_controller? @@ -97,23 +98,6 @@ module Devise request.env["devise.allow_params_authentication"] = true end - # Returns and delete (if it's navigational format) the url stored in the session for - # the given scope. Useful for giving redirect backs after sign up: - # - # Example: - # - # redirect_to stored_location_for(:user) || root_path - # - def stored_location_for(resource_or_scope) - scope = Devise::Mapping.find_scope!(resource_or_scope) - - if is_navigational_format? - session.delete("#{scope}_return_to") - else - session["#{scope}_return_to"] - end - end - # The scope root url to be used when he's signed in. By default, it first # tries to find a resource_root_path, otherwise it uses the root_path. def signed_in_root_path(resource_or_scope) diff --git a/lib/devise/controllers/store_location.rb b/lib/devise/controllers/store_location.rb new file mode 100644 index 00000000..845c54b1 --- /dev/null +++ b/lib/devise/controllers/store_location.rb @@ -0,0 +1,45 @@ +module Devise + module Controllers + # Provide the ability to store a location. + # Used to redirect back to a desired path after sign in. + # Included by default in all controllers. + module StoreLocation + # Returns and delete (if it's navigational format) the url stored in the session for + # the given scope. Useful for giving redirect backs after sign up: + # + # Example: + # + # redirect_to stored_location_for(:user) || root_path + # + def stored_location_for(resource_or_scope) + session_key = stored_location_key_for(resource_or_scope) + + if is_navigational_format? + session.delete(session_key) + else + session[session_key] + end + end + + # Stores the provided location to redirect the user after signing in. + # Useful in combination with the `stored_location_for` helper. + # + # Example: + # + # store_location_for(:user, dashboard_path) + # redirect_to user_omniauth_authorize_path(:facebook) + # + def store_location_for(resource_or_scope, location) + session_key = stored_location_key_for(resource_or_scope) + session[session_key] = location + end + + private + + def stored_location_key_for(resource_or_scope) + scope = Devise::Mapping.find_scope!(resource_or_scope) + "#{scope}_return_to" + end + end + end +end diff --git a/lib/devise/failure_app.rb b/lib/devise/failure_app.rb index 5be1acbe..34f6a5c5 100644 --- a/lib/devise/failure_app.rb +++ b/lib/devise/failure_app.rb @@ -13,6 +13,8 @@ module Devise include Rails.application.routes.url_helpers include Rails.application.routes.mounted_helpers + include Devise::Controllers::StoreLocation + delegate :flash, :to => :request def self.call(env) @@ -189,7 +191,7 @@ module Devise # yet, but we still need to store the uri based on scope, so different scopes # would never use the same uri to redirect. def store_location! - session["#{scope}_return_to"] = attempted_path if request.get? && !http_auth? + store_location_for(scope, attempted_path) if request.get? && !http_auth? end def is_navigational_format? diff --git a/test/controllers/helpers_test.rb b/test/controllers/helpers_test.rb index f65b2959..9b10587d 100644 --- a/test/controllers/helpers_test.rb +++ b/test/controllers/helpers_test.rb @@ -187,6 +187,17 @@ class ControllerAuthenticatableTest < ActionController::TestCase assert_nil @controller.session[:"user_return_to"] end + test 'store location for stores a location to redirect back to' do + assert_nil @controller.stored_location_for(:user) + @controller.store_location_for(:user, "/foo.bar") + assert_equal "/foo.bar", @controller.stored_location_for(:user) + end + + test 'store location for accepts a resource as argument' do + @controller.store_location_for(User.new, "/foo.bar") + assert_equal "/foo.bar", @controller.stored_location_for(User.new) + 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