From 4a0b9c663ac36beacbae0f922fcfe9e5e8551ec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 19 Feb 2010 09:52:04 +0100 Subject: [PATCH] Use metal for Devise::FailureApp. \m/ --- lib/devise/failure_app.rb | 67 ++++++++++++++++++------------------- test/failure_app_test.rb | 21 +++++------- test/support/integration.rb | 2 +- 3 files changed, 42 insertions(+), 48 deletions(-) diff --git a/lib/devise/failure_app.rb b/lib/devise/failure_app.rb index 6da47c75..eaae4496 100644 --- a/lib/devise/failure_app.rb +++ b/lib/devise/failure_app.rb @@ -1,57 +1,54 @@ +require "action_controller/metal" + module Devise # Failure application that will be called every time :warden is thrown from # any strategy or hook. Responsible for redirect the user to the sign in # page based on current scope and mapping. If no scope is given, redirect # to the default_url. - class FailureApp - attr_reader :env - include Warden::Mixins::Common + class FailureApp < ActionController::Metal + include ActionController::RackDelegation + include ActionController::UrlFor + include ActionController::Redirecting - cattr_accessor :default_url, :default_message, :instance_writer => false - @@default_message = :unauthenticated + mattr_accessor :default_message + self.default_message = :unauthenticated def self.call(env) - new(env).respond! + action(:respond).call(env) end - def initialize(env) - @env = env + def self.default_url_options(*args) + ApplicationController.default_url_options(*args) end - def respond! - options = @env['warden.options'] - scope = options[:scope] - - redirect_path = if mapping = Devise.mappings[scope] - "#{mapping.parsed_path}/#{mapping.path_names[:sign_in]}" - else - "/#{default_url}" - end - query_string = query_string_for(options) + def respond + scope = env['warden.options'][:scope] store_location!(scope) - - headers = {} - headers["Location"] = redirect_path - headers["Location"] << "?" << query_string unless query_string.empty? - headers["Content-Type"] = 'text/plain' - - [302, headers, ["You are being redirected to #{redirect_path}"]] + redirect_to send(:"new_#{scope}_session_path", query_string_params) end + protected + # Build the proper query string based on the given message. - def query_string_for(options) - message = @env['warden'].try(:message) || options[:message] || default_message + def query_string_params + message = warden.try(:message) || warden_options[:message] || self.class.default_message - params = case message - when Symbol - { message => true } - when String - { :message => message } - else - {} + case message + when Symbol + { message => true } + when String + { :message => message } + else + {} end + end - Rack::Utils.build_query(params) + def warden + env['warden'] + end + + def warden_options + env['warden.options'] end # Stores requested uri to redirect the user after signing in. We cannot use diff --git a/test/failure_app_test.rb b/test/failure_app_test.rb index cd9461d3..17cfd0d2 100644 --- a/test/failure_app_test.rb +++ b/test/failure_app_test.rb @@ -7,6 +7,7 @@ class FailureTest < ActiveSupport::TestCase env = { 'warden.options' => { :scope => :user }, 'REQUEST_URI' => 'http://test.host/', + 'HTTP_HOST' => 'test.host', 'REQUEST_METHOD' => 'GET', 'rack.session' => {} }.merge!(env_params) @@ -18,32 +19,28 @@ class FailureTest < ActiveSupport::TestCase end test 'return to the default redirect location' do - assert_equal '/users/sign_in?unauthenticated=true', call_failure.second['Location'] + assert_equal 'http://test.host/users/sign_in?unauthenticated=true', call_failure.second['Location'] end test 'uses the proxy failure message' do warden = OpenStruct.new(:message => :test) location = call_failure('warden' => warden).second['Location'] - assert_equal '/users/sign_in?test=true', location + assert_equal 'http://test.host/users/sign_in?test=true', location end test 'uses the given message' do warden = OpenStruct.new(:message => 'Hello world') location = call_failure('warden' => warden).second['Location'] - assert_equal '/users/sign_in?message=Hello+world', location + assert_equal 'http://test.host/users/sign_in?message=Hello+world', location end - test 'setup default url' do - Devise::FailureApp.default_url = 'test/sign_in' - location = call_failure('warden.options' => { :scope => nil }).second['Location'] - assert_equal '/test/sign_in?unauthenticated=true', location - end - - test 'set content type to default text/plain' do - assert_equal 'text/plain', call_failure.second['Content-Type'] + test 'set content type to default text/html' do + assert_equal 'text/html; charset=utf-8', call_failure.second['Content-Type'] end test 'setup a default message' do - assert_equal ['You are being redirected to /users/sign_in?unauthenticated=true'], call_failure.last + assert_match /You are being/, call_failure.last.body + assert_match /redirected/, call_failure.last.body + assert_match /\?unauthenticated=true/, call_failure.last.body end end diff --git a/test/support/integration.rb b/test/support/integration.rb index a38e6bff..6607874b 100644 --- a/test/support/integration.rb +++ b/test/support/integration.rb @@ -50,7 +50,7 @@ class ActionController::IntegrationTest end def assert_current_path(path) - assert_equal path, current_url + assert_equal(prepend_host(path), prepend_host(current_url)) end # Fix assert_redirect_to in integration sessions because they don't take into