Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 7640

Show
Ignore:
Timestamp:
09/26/07 01:24:07 (2 years ago)
Author:
bitsweat
Message:

Move Railties' Dispatcher to ActionController::Dispatcher, introduce before_ and after_dispatch callbacks, and warm up to non-CGI requests.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/actionpack/CHANGELOG

    r7608 r7640  
    11*SVN* 
     2 
     3* Move Railties' Dispatcher to ActionController::Dispatcher, introduce before_ and after_dispatch callbacks, and warm up to non-CGI requests.  [Jeremy Kemper] 
    24 
    35* The tag helper may bypass escaping.  [Jeremy Kemper] 
  • trunk/actionpack/lib/action_controller/dispatcher.rb

    r7475 r7640  
    1 #-- 
    2 # Copyright (c) 2004-2007 David Heinemeier Hansson 
    3 
    4 # Permission is hereby granted, free of charge, to any person obtaining 
    5 # a copy of this software and associated documentation files (the 
    6 # "Software"), to deal in the Software without restriction, including 
    7 # without limitation the rights to use, copy, modify, merge, publish, 
    8 # distribute, sublicense, and/or sell copies of the Software, and to 
    9 # permit persons to whom the Software is furnished to do so, subject to 
    10 # the following conditions: 
    11 
    12 # The above copyright notice and this permission notice shall be 
    13 # included in all copies or substantial portions of the Software. 
    14 
    15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
    16 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 
    17 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
    18 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 
    19 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
    20 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 
    21 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
    22 #++ 
     1module ActionController 
     2  # Dispatches requests to the appropriate controller and takes care of 
     3  # reloading the app after each request when Dependencies.load? is true. 
     4  class Dispatcher 
     5    class << self 
     6      # Backward-compatible class method takes CGI-specific args. Deprecated 
     7      # in favor of Dispatcher.new(output, request, response).dispatch! 
     8      def dispatch(cgi = nil, session_options = CgiRequest::DEFAULT_SESSION_OPTIONS, output = $stdout) 
     9        new(output).dispatch_cgi(cgi, session_options) 
     10      end 
    2311 
    24 # This class provides an interface for dispatching a CGI (or CGI-like) request 
    25 # to the appropriate controller and action. It also takes care of resetting 
    26 # the environment (when Dependencies.load? is true) after each request. 
    27 class Dispatcher 
    28   class << self 
    29     # Dispatch the given CGI request, using the given session options, and 
    30     # emitting the output via the given output.  If you dispatch with your 
    31     # own CGI object be sure to handle the exceptions it raises on multipart 
    32     # requests (EOFError and ArgumentError). 
    33     def dispatch(cgi = nil, session_options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, output = $stdout) 
    34       controller = nil 
    35       if cgi ||= new_cgi(output) 
    36         request, response = ActionController::CgiRequest.new(cgi, session_options), ActionController::CgiResponse.new(cgi) 
    37         prepare_application 
    38         controller = ActionController::Routing::Routes.recognize(request) 
    39         controller.process(request, response).out(output) 
     12      # Declare a block to be called before each dispatch. 
     13      # Run in the order declared. 
     14      def before_dispatch(*method_names, &block) 
     15        callbacks[:before].concat method_names 
     16        callbacks[:before] << block if block_given? 
    4017      end 
    41     rescue Exception => exception  # errors from CGI dispatch 
    42       failsafe_response(cgi, output, '500 Internal Server Error', exception) do 
    43         controller ||= (ApplicationController rescue ActionController::Base) 
    44         controller.process_with_exception(request, response, exception).out(output) 
     18 
     19      # Declare a block to be called after each dispatch. 
     20      # Run in reverse of the order declared. 
     21      def after_dispatch(*method_names, &block) 
     22        callbacks[:after].concat method_names 
     23        callbacks[:after] << block if block_given? 
    4524      end 
    46     ensure 
    47       # Do not give a failsafe response here. 
    48       reset_after_dispatch 
    49     end 
    5025 
    51     # Reset the application by clearing out loaded controllers, views, actions, 
    52     # mailers, and so forth. This allows them to be loaded again without having 
    53     # to restart the server (WEBrick, FastCGI, etc.). 
    54     def reset_application! 
    55       ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord) 
    56  
    57       Dependencies.clear 
    58  
    59       ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord) 
    60     end 
    61  
    62     # Add a preparation callback. Preparation callbacks are run before every 
    63     # request in development mode, and before the first request in production 
    64     # mode. 
    65     #  
    66     # An optional identifier may be supplied for the callback. If provided, 
    67     # to_prepare may be called again with the same identifier to replace the 
    68     # existing callback. Passing an identifier is a suggested practice if the 
    69     # code adding a preparation block may be reloaded. 
    70     def to_prepare(identifier = nil, &block) 
    71       unless identifier.nil? 
    72         callback = preparation_callbacks.detect { |ident, _| ident == identifier } 
    73  
    74         if callback # Already registered: update the existing callback 
    75           callback[-1] = block 
    76           return 
     26      # Add a preparation callback. Preparation callbacks are run before every 
     27      # request in development mode, and before the first request in production 
     28      # mode. 
     29      #  
     30      # An optional identifier may be supplied for the callback. If provided, 
     31      # to_prepare may be called again with the same identifier to replace the 
     32      # existing callback. Passing an identifier is a suggested practice if the 
     33      # code adding a preparation block may be reloaded. 
     34      def to_prepare(identifier = nil, &block) 
     35        # Already registered: update the existing callback 
     36        if identifier 
     37          if callback = callbacks[:prepare].assoc(identifier) 
     38            callback[1] = block 
     39          else 
     40            callbacks[:prepare] << [identifier, block] 
     41          end 
     42        else 
     43          callbacks[:prepare] << block 
    7744        end 
    7845      end 
    7946 
    80       preparation_callbacks << [identifier, block] 
    81  
    82       return 
    83     end 
    84  
    85     private 
    86       attr_accessor_with_default :preparation_callbacks, [] 
    87       attr_accessor_with_default :preparation_callbacks_run, false 
    88  
    89       # CGI.new plus exception handling.  CGI#read_multipart raises EOFError 
    90       # if body.empty? or body.size != Content-Length and raises ArgumentError 
    91       # if Content-Length is non-integer. 
    92       def new_cgi(output) 
    93         failsafe_response(nil, output, '400 Bad Request') { CGI.new } 
    94       end 
    95  
    96       def prepare_application 
    97         if Dependencies.load? 
    98           ActionController::Routing::Routes.reload 
    99           self.preparation_callbacks_run = false 
    100         end 
    101  
    102         require_dependency 'application' unless Object.const_defined?(:ApplicationController) 
    103         ActiveRecord::Base.verify_active_connections! if defined?(ActiveRecord) 
    104         run_preparation_callbacks 
    105       end 
    106  
    107       def reset_after_dispatch 
    108         reset_application! if Dependencies.load? 
    109       end 
    110  
    111       def run_preparation_callbacks 
    112         return if preparation_callbacks_run 
    113         preparation_callbacks.each { |_, callback| callback.call } 
    114         self.preparation_callbacks_run = true 
    115       end 
    116  
    11747      # If the block raises, send status code as a last-ditch response. 
    118       def failsafe_response(cgi, fallback_output, status, exception = nil) 
     48      def failsafe_response(fallback_output, status, originating_exception = nil) 
    11949        yield 
    120       rescue Exception 
     50      rescue Exception => exception 
    12151        begin 
    122           log_failsafe_exception(cgi, status, exception) 
    123  
     52          log_failsafe_exception(status, originating_exception || exception) 
    12453          body = failsafe_response_body(status) 
    125           if cgi 
    126             head = { 'status' => status, 'type' => 'text/html' } 
    127  
    128             # FIXME: using CGI differently than CGIResponse does breaks 
    129             # the Mongrel CGI wrapper. 
    130             if defined?(Mongrel) && cgi.is_a?(Mongrel::CGIWrapper) 
    131               # FIXME: set a dummy cookie so the Mongrel CGI wrapper will 
    132               # also consider @output_cookies (used for session cookies.) 
    133               head['cookie'] = [] 
    134               cgi.header(head) 
    135               fallback_output << body 
    136             else 
    137               cgi.out(head) { body } 
    138             end 
    139           else 
    140             fallback_output.write "Status: #{status}\r\nContent-Type: text/html\r\n\r\n#{body}" 
    141           end 
     54          fallback_output.write "Status: #{status}\r\nContent-Type: text/html\r\n\r\n#{body}" 
    14255          nil 
    143         rescue Exception  # Logger or IO errors 
     56        rescue Exception => failsafe_error # Logger or IO errors 
     57          $stderr.puts "Error during failsafe response: #{failsafe_error}" 
     58          $stderr.puts "(originally #{originating_exception})" if originating_exception 
    14459        end 
    14560      end 
    14661 
    147       def failsafe_response_body(status) 
    148         error_path = "#{RAILS_ROOT}/public/#{status[0..3]}.html" 
     62      private 
     63        def failsafe_response_body(status) 
     64          error_path = "#{error_file_path}/#{status.to_s[0..3]}.html" 
    14965 
    150         if File.exists?(error_path) 
    151           File.read(error_path) 
    152         else 
    153           "<html><body><h1>#{status}</h1></body></html>" 
     66          if File.exist?(error_path) 
     67            File.read(error_path) 
     68          else 
     69            "<html><body><h1>#{status}</h1></body></html>" 
     70          end 
     71        end 
     72 
     73        def log_failsafe_exception(status, exception) 
     74          message = "/!\ FAILSAFE /!\  #{Time.now}\n  Status: #{status}\n" 
     75          message << "  #{exception}\n    #{exception.backtrace.join("\n    ")}" if exception 
     76          failsafe_logger.fatal message 
     77        end 
     78 
     79        def failsafe_logger 
     80          if defined?(::RAILS_DEFAULT_LOGGER) && !::RAILS_DEFAULT_LOGGER.nil? 
     81            ::RAILS_DEFAULT_LOGGER 
     82          else 
     83            Logger.new($stderr) 
     84          end 
     85        end 
     86    end 
     87 
     88    cattr_accessor :error_file_path 
     89    self.error_file_path = "#{::RAILS_ROOT}/public" if defined? ::RAILS_ROOT 
     90 
     91    cattr_accessor :callbacks 
     92    self.callbacks = Hash.new { |h, k| h[k] = [] } 
     93 
     94    attr_accessor_with_default :unprepared, true 
     95 
     96 
     97    before_dispatch :reload_application 
     98    before_dispatch :prepare_application 
     99    after_dispatch :flush_logger 
     100    after_dispatch :cleanup_application 
     101 
     102    def initialize(output, request = nil, response = nil) 
     103      @output, @request, @response = output, request, response 
     104    end 
     105 
     106    def dispatch 
     107      run_callbacks :before 
     108      handle_request 
     109    rescue Exception => exception 
     110      failsafe_rescue exception 
     111    ensure 
     112      run_callbacks :after, :reverse_each 
     113    end 
     114 
     115    def dispatch_cgi(cgi, session_options) 
     116      if cgi ||= self.class.failsafe_response(@output, '400 Bad Request') { CGI.new } 
     117        @request = CgiRequest.new(cgi, session_options) 
     118        @response = CgiResponse.new(cgi) 
     119        dispatch 
     120      end 
     121    rescue Exception => exception 
     122      failsafe_rescue exception 
     123    end 
     124 
     125    def reload_application 
     126      if Dependencies.load? 
     127        Routing::Routes.reload 
     128        self.unprepared = true 
     129      end 
     130    end 
     131 
     132    def prepare_application(force = false) 
     133      require_dependency 'application' unless defined?(::ApplicationController) 
     134      ActiveRecord::Base.verify_active_connections! if defined?(ActiveRecord) 
     135 
     136      if unprepared || force 
     137        run_callbacks :prepare 
     138        self.unprepared = false 
     139      end 
     140    end 
     141 
     142    # Cleanup the application by clearing out loaded classes so they can 
     143    # be reloaded on the next request without restarting the server. 
     144    def cleanup_application(force = false) 
     145      if Dependencies.load? || force 
     146        ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord) 
     147        Dependencies.clear 
     148        ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord) 
     149      end 
     150    end 
     151 
     152    def flush_logger 
     153      RAILS_DEFAULT_LOGGER.flush if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER.respond_to?(:flush) 
     154    end 
     155 
     156    protected 
     157      def handle_request 
     158        @controller = Routing::Routes.recognize(@request) 
     159        @controller.process(@request, @response).out(@output) 
     160      end 
     161 
     162      def run_callbacks(kind, enumerator = :each) 
     163        callbacks[kind].send(enumerator) do |callback| 
     164          case callback 
     165          when Proc; callback.call(self) 
     166          when String, Symbol; send(callback) 
     167          when Array; callback[1].call(self) 
     168          else raise ArgumentError, "Unrecognized callback #{callback.inspect}" 
     169          end 
    154170        end 
    155171      end 
    156172 
    157       def log_failsafe_exception(cgi, status, exception) 
    158         fell_back = cgi ? 'has cgi' : 'no cgi, fallback ouput' 
    159         message = "DISPATCHER FAILSAFE RESPONSE (#{fell_back}) #{Time.now}\n  Status: #{status}\n" 
    160         message << "  #{exception}\n    #{exception.backtrace.join("\n    ")}" if exception 
    161         failsafe_logger.fatal message 
    162       end 
    163  
    164       def failsafe_logger 
    165         if defined?(RAILS_DEFAULT_LOGGER) && !RAILS_DEFAULT_LOGGER.nil? 
    166           RAILS_DEFAULT_LOGGER 
    167         else 
    168           Logger.new($stderr) 
     173      def failsafe_rescue(exception) 
     174        self.class.failsafe_response(@output, '500 Internal Server Error', exception) do 
     175          if @controller ||= defined?(::ApplicationController) ? ::ApplicationController : Base 
     176            @controller.process_with_exception(@request, @response, exception).out(@output) 
     177          else 
     178            raise exception 
     179          end 
    169180        end 
    170181      end 
    171182  end 
    172183end 
    173  
    174 Dispatcher.to_prepare :activerecord_instantiate_observers do 
    175   ActiveRecord::Base.instantiate_observers 
    176 end if defined?(ActiveRecord) 
  • trunk/actionpack/test/abstract_unit.rb

    r6876 r7640  
    3131  end 
    3232  yield 
    33 rescue LoadError 
     33rescue LoadError => load_error 
     34  raise unless load_error.message =~ /mocha/i 
    3435  $stderr.puts "Skipping #{test_name} tests. `gem install mocha` and try again." 
    3536end 
  • trunk/actionpack/test/controller/dispatcher_test.rb

    r7591 r7640  
    1 require "#{File.dirname(__FILE__)}/abstract_unit" 
     1require "#{File.dirname(__FILE__)}/../abstract_unit" 
    22 
    33uses_mocha 'dispatcher tests' do 
    44 
    5 $:.unshift File.dirname(__FILE__) + "/../../actionmailer/lib" 
    6  
    7 require 'stringio' 
    8 require 'cgi' 
    9  
    10 require 'dispatcher' 
    11 require 'action_controller' 
    12 require 'action_mailer' 
    13  
     5require 'action_controller/dispatcher' 
    146 
    157class DispatcherTest < Test::Unit::TestCase 
     8  Dispatcher = ActionController::Dispatcher 
     9 
    1610  def setup 
    1711    @output = StringIO.new 
    18     ENV['REQUEST_METHOD'] = "GET" 
     12    ENV['REQUEST_METHOD'] = 'GET' 
    1913 
    20     Dispatcher.send(:preparation_callbacks).clear 
    21     Dispatcher.send(:preparation_callbacks_run=, false) 
    22  
    23     Object.const_set 'ApplicationController', nil 
     14    Dispatcher.callbacks[:prepare].clear 
     15    @dispatcher = Dispatcher.new(@output) 
    2416  end 
    2517 
    2618  def teardown 
    2719    ENV['REQUEST_METHOD'] = nil 
    28     Object.send :remove_const, 'ApplicationController' 
    2920  end 
    3021 
     
    3829  end 
    3930 
    40   def test_clears_dependencies_after_dispatch_if_not_in_loading_mode 
     31  def test_leaves_dependencies_after_dispatch_if_not_in_loading_mode 
    4132    Dependencies.stubs(:load?).returns(false) 
    4233 
     
    5849  end 
    5950 
    60   def test_preparation_callbacks 
    61     ActionController::Routing::Routes.stubs(:reload) 
     51  def test_reload_application_sets_unprepared_if_loading_dependencies 
     52    Dependencies.stubs(:load?).returns(false) 
     53    ActionController::Routing::Routes.expects(:reload).never 
     54    @dispatcher.unprepared = false 
     55    @dispatcher.send(:reload_application) 
     56    assert !@dispatcher.unprepared 
    6257 
    63     old_mechanism = Dependencies.mechanism 
    64      
     58    Dependencies.stubs(:load?).returns(true) 
     59    ActionController::Routing::Routes.expects(:reload).once 
     60    @dispatcher.send(:reload_application) 
     61    assert @dispatcher.unprepared 
     62  end 
     63 
     64  def test_prepare_application_runs_callbacks_if_unprepared 
    6565    a = b = c = nil 
    6666    Dispatcher.to_prepare { a = b = c = 1 } 
    6767    Dispatcher.to_prepare { b = c = 2 } 
    6868    Dispatcher.to_prepare { c = 3 } 
    69      
    70     Dispatcher.send :prepare_application 
    71      
     69 
     70    # Skip the callbacks when already prepared. 
     71    @dispatcher.unprepared = false 
     72    @dispatcher.send :prepare_application 
     73    assert_nil a || b || c 
     74 
     75    # Perform the callbacks when unprepared. 
     76    @dispatcher.unprepared = true 
     77    @dispatcher.send :prepare_application 
    7278    assert_equal 1, a 
    7379    assert_equal 2, b 
    7480    assert_equal 3, c 
    75      
    76     # When mechanism is :load, perform the callbacks each request: 
    77     Dependencies.mechanism = :load 
    78     a = b = c = nil 
    79     Dispatcher.send :prepare_application 
    80     assert_equal 1, a 
    81     assert_equal 2, b 
    82     assert_equal 3, c 
    83      
     81 
    8482    # But when not :load, make sure they are only run once 
    8583    a = b = c = nil 
    86     Dependencies.mechanism = :not_load 
    87     Dispatcher.send :prepare_application 
    88     assert_equal nil, a || b || c 
    89   ensure 
    90     Dependencies.mechanism = old_mechanism 
     84    @dispatcher.send :prepare_application 
     85    assert_nil a || b || c 
    9186  end 
    92    
     87 
    9388  def test_to_prepare_with_identifier_replaces 
    94     ActionController::Routing::Routes.stubs(:reload) 
    95  
    9689    a = b = nil 
    9790    Dispatcher.to_prepare(:unique_id) { a = b = 1 } 
    9891    Dispatcher.to_prepare(:unique_id) { a = 2 } 
    99      
    100     Dispatcher.send :prepare_application 
     92 
     93    @dispatcher.unprepared = true 
     94    @dispatcher.send :prepare_application 
    10195    assert_equal 2, a 
    10296    assert_equal nil, b 
     
    119113end 
    120114 
    121 end # uses_mocha 
     115end 
  • trunk/railties/CHANGELOG

    r7626 r7640  
    11*SVN* 
     2 
     3* Moved Dispatcher to ActionController::Dispatcher.  [Jeremy Kemper] 
    24 
    35* Changed the default logger from Ruby's own Logger with the clean_logger extensions to ActiveSupport::BufferedLogger for performance reasons [DHH]. (You can change it back with config.logger = Logger.new("/path/to/log", level).) 
  • trunk/railties/lib/console_app.rb

    r7628 r7640  
    2424def reload! 
    2525  puts "Reloading..." 
    26   returning Dispatcher.reset_application! do 
    27     Dispatcher.send :run_preparation_callbacks 
    28   end 
     26  dispatcher = ActionController::Dispatcher.new($stdout) 
     27  dispatcher.cleanup_application(true) 
     28  dispatcher.prepare_application(true) 
     29  true 
    2930end 
  • trunk/railties/lib/dispatcher.rb

    r7626 r7640  
    2121# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
    2222#++ 
    23  
    24 # This class provides an interface for dispatching a CGI (or CGI-like) request 
    25 # to the appropriate controller and action. It also takes care of resetting 
    26 # the environment (when Dependencies.load? is true) after each request. 
    27 class Dispatcher 
    28   class << self 
    29     # Dispatch the given CGI request, using the given session options, and 
    30     # emitting the output via the given output.  If you dispatch with your 
    31     # own CGI object be sure to handle the exceptions it raises on multipart 
    32     # requests (EOFError and ArgumentError). 
    33     def dispatch(cgi = nil, session_options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS, output = $stdout) 
    34       controller = nil 
    35       if cgi ||= new_cgi(output) 
    36         request, response = ActionController::CgiRequest.new(cgi, session_options), ActionController::CgiResponse.new(cgi) 
    37         prepare_application 
    38         controller = ActionController::Routing::Routes.recognize(request) 
    39         controller.process(request, response).out(output) 
    40       end 
    41     rescue Exception => exception # errors from CGI dispatch 
    42       failsafe_response(cgi, output, '500 Internal Server Error', exception) do 
    43         controller ||= (ApplicationController rescue ActionController::Base) 
    44         controller.process_with_exception(request, response, exception).out(output) 
    45       end 
    46     ensure 
    47       # Do not give a failsafe response here 
    48       flush_logger 
    49       reset_after_dispatch 
    50     end 
    51  
    52     # Reset the application by clearing out loaded controllers, views, actions, 
    53     # mailers, and so forth. This allows them to be loaded again without having 
    54     # to restart the server (WEBrick, FastCGI, etc.). 
    55     def reset_application! 
    56       ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord) 
    57  
    58       Dependencies.clear 
    59  
    60       ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord) 
    61     end 
    62  
    63     # Add a preparation callback. Preparation callbacks are run before every 
    64     # request in development mode, and before the first request in production 
    65     # mode. 
    66     #  
    67     # An optional identifier may be supplied for the callback. If provided, 
    68     # to_prepare may be called again with the same identifier to replace the 
    69     # existing callback. Passing an identifier is a suggested practice if the 
    70     # code adding a preparation block may be reloaded. 
    71     def to_prepare(identifier = nil, &block) 
    72       unless identifier.nil? 
    73         callback = preparation_callbacks.detect { |ident, _| ident == identifier } 
    74  
    75         if callback # Already registered: update the existing callback 
    76           callback[-1] = block 
    77           return 
    78         end 
    79       end 
    80  
    81       preparation_callbacks << [identifier, block] 
    82  
    83       return 
    84     end 
    85  
    86     private 
    87       attr_accessor_with_default :preparation_callbacks, [] 
    88       attr_accessor_with_default :preparation_callbacks_run, false 
    89  
    90       # CGI.new plus exception handling.  CGI#read_multipart raises EOFError 
    91       # if body.empty? or body.size != Content-Length and raises ArgumentError 
    92       # if Content-Length is non-integer. 
    93       def new_cgi(output) 
    94         failsafe_response(nil, output, '400 Bad Request') { CGI.new } 
    95       end 
    96  
    97       def prepare_application 
    98         if Dependencies.load? 
    99           ActionController::Routing::Routes.reload 
    100           self.preparation_callbacks_run = false 
    101         end 
    102  
    103         require_dependency 'application' unless Object.const_defined?(:ApplicationController) 
    104         ActiveRecord::Base.verify_active_connections! if defined?(ActiveRecord) 
    105         run_preparation_callbacks 
    106       end 
    107  
    108       def reset_after_dispatch 
    109         reset_application! if Dependencies.load? 
    110       end 
    111  
    112       def run_preparation_callbacks 
    113         return if preparation_callbacks_run 
    114         preparation_callbacks.each { |_, callback| callback.call } 
    115         self.preparation_callbacks_run = true 
    116       end 
    117  
    118       # If the block raises, send status code as a last-ditch response. 
    119       def failsafe_response(cgi, fallback_output, status, exception = nil) 
    120         yield 
    121       rescue Exception 
    122         begin 
    123           log_failsafe_exception(cgi, status, exception) 
    124  
    125           body = failsafe_response_body(status) 
    126           if cgi 
    127             head = { 'status' => status, 'type' => 'text/html' } 
    128  
    129             # FIXME: using CGI differently than CGIResponse does breaks 
    130             # the Mongrel CGI wrapper. 
    131             if defined?(Mongrel) && cgi.is_a?(Mongrel::CGIWrapper) 
    132               # FIXME: set a dummy cookie so the Mongrel CGI wrapper will 
    133               # also consider @output_cookies (used for session cookies.) 
    134               head['cookie'] = [] 
    135               cgi.header(head) 
    136               fallback_output << body 
    137             else 
    138               cgi.out(head) { body } 
    139             end 
    140           else 
    141             fallback_output.write "Status: #{status}\r\nContent-Type: text/html\r\n\r\n#{body}" 
    142           end 
    143           nil 
    144         rescue Exception  # Logger or IO errors 
    145         end 
    146       end 
    147  
    148       def failsafe_response_body(status) 
    149         error_path = "#{RAILS_ROOT}/public/#{status[0..3]}.html" 
    150  
    151         if File.exists?(error_path) 
    152           File.read(error_path) 
    153         else 
    154           "<html><body><h1>#{status}</h1></body></html>" 
    155         end 
    156       end 
    157  
    158       def log_failsafe_exception(cgi, status, exception) 
    159         fell_back = cgi ? 'has cgi' : 'no cgi, fallback ouput' 
    160         message = "DISPATCHER FAILSAFE RESPONSE (#{fell_back}) #{Time.now}\n  Status: #{status}\n" 
    161         message << "  #{exception}\n    #{exception.backtrace.join("\n    ")}" if exception 
    162         failsafe_logger.fatal message 
    163       end 
    164  
    165       def failsafe_logger 
    166         if defined?(RAILS_DEFAULT_LOGGER) && !RAILS_DEFAULT_LOGGER.nil? 
    167           RAILS_DEFAULT_LOGGER 
    168         else 
    169           ActiveSupport::BufferedLogger.new($stderr) 
    170         end 
    171       end 
    172        
    173       def flush_logger 
    174         RAILS_DEFAULT_LOGGER.flush if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER.respond_to?(:flush) 
    175       end 
    176   end 
    177 end 
    178  
    179 Dispatcher.to_prepare :activerecord_instantiate_observers do 
    180   ActiveRecord::Base.instantiate_observers 
    181 end if defined?(ActiveRecord) 
     23require 'action_controller/dispatcher' 
     24Dispatcher = ActionController::Dispatcher 
  • trunk/railties/Rakefile

    r7619 r7640  
    2121RUBY_FORGE_USER    = "webster132" 
    2222 
     23 
     24task :default => :test 
    2325 
    2426## This is required until the regular test task 
  • trunk/railties/test/console_app_test.rb

    r6898 r7640  
    22 
    33require 'action_controller' # console_app uses 'action_controller/integration' 
     4 
     5unless defined? ApplicationController 
     6  class ApplicationController < ActionController::Base; end 
     7end 
    48 
    59require 'dispatcher'