Ticket #10795: refactor_dispatcher.patch
| File refactor_dispatcher.patch, 10.7 kB (added by lifofifo, 6 months ago) |
|---|
-
a/actionpack/lib/action_controller.rb
old new 56 56 require 'action_controller/record_identifier' 57 57 require 'action_controller/request_forgery_protection' 58 58 require 'action_controller/headers' 59 require 'action_controller/dispatcher_callbacks' 59 60 60 61 require 'action_view' 61 62 ActionController::Base.template_class = ActionView::Base -
a/actionpack/lib/action_controller/dispatcher.rb
old new 3 3 # reloading the app after each request when Dependencies.load? is true. 4 4 class Dispatcher 5 5 @@guard = Mutex.new 6 6 7 include DispatcherCallbacks 8 7 9 class << self 8 10 # Backward-compatible class method takes CGI-specific args. Deprecated 9 11 # in favor of Dispatcher.new(output, request, response).dispatch. … … 60 62 $stderr.puts "(originally #{originating_exception})" if originating_exception 61 63 end 62 64 end 65 66 def define_dispatcher_callbacks(cache_classes = true) 67 unless cache_classes 68 # Development mode callbacks 69 before_dispatch :reload_application 70 after_dispatch :cleanup_application 71 end 72 73 # Common callbacks 74 to_prepare :load_application_controller do 75 begin 76 require_dependency 'application' unless defined?(::ApplicationController) 77 rescue LoadError => error 78 raise unless error.message =~ /application\.rb/ 79 end 80 end 81 82 if defined? ActiveRecord 83 before_dispatch :active_record_callbacks 84 to_prepare :activerecord_instantiate_observers do 85 ActiveRecord::Base.instantiate_observers 86 end 87 end 88 89 after_dispatch :flush_logger 90 end 63 91 64 92 private 65 93 def failsafe_response_body(status) … … 93 121 cattr_accessor :callbacks 94 122 self.callbacks = Hash.new { |h, k| h[k] = [] } 95 123 96 cattr_accessor :unprepared97 self.unprepared = true98 99 100 before_dispatch :reload_application101 before_dispatch :prepare_application102 after_dispatch :flush_logger103 after_dispatch :cleanup_application104 105 if defined? ActiveRecord106 to_prepare :activerecord_instantiate_observers do107 ActiveRecord::Base.instantiate_observers108 end109 end110 111 124 def initialize(output, request = nil, response = nil) 112 125 @output, @request, @response = output, request, response 113 126 end … … 135 148 failsafe_rescue exception 136 149 end 137 150 138 def reload_application139 if Dependencies.load?140 Routing::Routes.reload141 self.unprepared = true142 end143 end144 145 def prepare_application(force = false)146 begin147 require_dependency 'application' unless defined?(::ApplicationController)148 rescue LoadError => error149 raise unless error.message =~ /application\.rb/150 end151 152 ActiveRecord::Base.verify_active_connections! if defined?(ActiveRecord)153 154 if unprepared || force155 run_callbacks :prepare156 self.unprepared = false157 end158 end159 160 # Cleanup the application by clearing out loaded classes so they can161 # be reloaded on the next request without restarting the server.162 def cleanup_application(force = false)163 if Dependencies.load? || force164 ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)165 Dependencies.clear166 ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)167 end168 end169 170 def flush_logger171 RAILS_DEFAULT_LOGGER.flush if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER.respond_to?(:flush)172 end173 174 151 protected 175 152 def handle_request 176 153 @controller = Routing::Routes.recognize(@request) -
/dev/null
old new 1 module ActionController #:nodoc: 2 module DispatcherCallbacks #:nodoc: 3 4 def reload_application 5 Routing::Routes.reload 6 run_callbacks :prepare 7 end 8 9 def active_record_callbacks 10 ActiveRecord::Base.verify_active_connections! if defined?(ActiveRecord) 11 end 12 13 # Cleanup the application by clearing out loaded classes so they can 14 # be reloaded on the next request without restarting the server. 15 def cleanup_application(force = false) 16 if Dependencies.load? || force 17 ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord) 18 Dependencies.clear 19 ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord) 20 end 21 end 22 23 def flush_logger 24 RAILS_DEFAULT_LOGGER.flush if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER.respond_to?(:flush) 25 end 26 27 end 28 end -
a/actionpack/test/controller/dispatcher_test.rb
old new 11 11 @output = StringIO.new 12 12 ENV['REQUEST_METHOD'] = 'GET' 13 13 14 Dispatcher.callbacks[:prepare].clear 15 @dispatcher = Dispatcher.new(@output) 14 Dispatcher.stubs(:require_dependency) 16 15 end 17 16 18 17 def teardown 18 Dispatcher.callbacks = Hash.new { |h, k| h[k] = [] } 19 19 ENV.delete 'REQUEST_METHOD' 20 20 end 21 21 22 22 def test_clears_dependencies_after_dispatch_if_in_loading_mode 23 prepare_dispatcher 24 23 25 Dependencies.stubs(:load?).returns(true) 24 26 25 27 ActionController::Routing::Routes.expects(:reload).once 26 28 Dependencies.expects(:clear).once 27 29 28 30 dispatch 29 31 end 30 32 31 33 def test_leaves_dependencies_after_dispatch_if_not_in_loading_mode 34 prepare_dispatcher(true) 35 32 36 Dependencies.stubs(:load?).returns(false) 33 37 34 38 ActionController::Routing::Routes.expects(:reload).never … … 38 42 end 39 43 40 44 def test_failsafe_response 45 prepare_dispatcher 46 41 47 CGI.expects(:new).raises('some multipart parsing failure') 42 48 43 49 ActionController::Routing::Routes.stubs(:reload) … … 48 54 assert_equal "Status: 400 Bad Request\r\nContent-Type: text/html\r\n\r\n<html><body><h1>400 Bad Request</h1></body></html>", @output.string 49 55 end 50 56 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 57 58 Dependencies.stubs(:load?).returns(true) 59 ActionController::Routing::Routes.expects(:reload).once 60 @dispatcher.send!(:reload_application) 61 assert @dispatcher.unprepared 57 def test_dispatcher_callbacks_if_loading_dependencies 58 prepare_dispatcher 59 60 Dispatcher.any_instance.expects(:reload_application) 61 Dispatcher.any_instance.expects(:cleanup_application) 62 63 dispatch 64 end 65 66 def test_dispatcher_callbacks_if_requiring_dependencies 67 prepare_dispatcher(true) 68 69 Dispatcher.any_instance.expects(:reload_application).never 70 Dispatcher.any_instance.expects(:cleanup_application).never 71 72 dispatch 62 73 end 63 74 64 def test_prepare_application_runs_callbacks_if_unprepared 75 def test_prepare_application_runs_callbacks_when_called 76 prepare_dispatcher(false, false) 77 65 78 a = b = c = nil 66 79 Dispatcher.to_prepare { a = b = c = 1 } 67 80 Dispatcher.to_prepare { b = c = 2 } 68 81 Dispatcher.to_prepare { c = 3 } 69 82 70 # Skip the callbacks when already prepared.71 @dispatcher.unprepared = false72 @dispatcher.send! :prepare_application73 83 assert_nil a || b || c 74 84 75 85 # Perform the callbacks when unprepared. 76 @dispatcher.unprepared = true77 86 @dispatcher.send! :prepare_application 78 87 assert_equal 1, a 79 88 assert_equal 2, b 80 89 assert_equal 3, c 81 90 82 # But when not :load, make sure they are only run once91 # make sure they are run everytime when cache_classes is false 83 92 a = b = c = nil 84 @dispatcher.send! :prepare_application 85 assert_nil a || b || c 93 94 dispatch 95 96 assert_equal 1, a 97 assert_equal 2, b 98 assert_equal 3, c 86 99 end 87 100 88 101 def test_to_prepare_with_identifier_replaces 102 prepare_dispatcher 103 89 104 a = b = nil 90 105 Dispatcher.to_prepare(:unique_id) { a = b = 1 } 91 106 Dispatcher.to_prepare(:unique_id) { a = 2 } 92 107 93 @dispatcher.unprepared = true 94 @dispatcher.send! :prepare_application 108 @dispatcher.send! :reload_application 95 109 assert_equal 2, a 96 110 assert_equal nil, b 97 111 end 98 112 99 def test_to_prepare_only_runs_once_if_not_loading_dependencies 113 def test_to_prepare_only_runs_once_if_not_loading_dependencies 100 114 Dependencies.stubs(:load?).returns(false) 101 115 called = 0 102 116 Dispatcher.to_prepare(:unprepared_test) { called += 1 } 117 118 prepare_dispatcher(true) 103 119 2.times { dispatch } 104 120 assert_equal 1, called 105 121 end 106 122 107 123 private 124 125 def prepare_dispatcher(cache_classes = false, prepare = true) 126 Dispatcher.define_dispatcher_callbacks(cache_classes) 127 128 @dispatcher = Dispatcher.new(@output) 129 @dispatcher.send(:run_callbacks, :prepare) if prepare 130 131 class << @dispatcher 132 def prepare_application 133 run_callbacks :prepare 134 end 135 end 136 end 137 108 138 def dispatch(output = @output) 109 139 controller = mock 110 140 controller.stubs(:process).returns(controller) -
a/railties/lib/initializer.rb
old new 97 97 after_initialize 98 98 99 99 load_application_initializers 100 101 # Prepare dispatcher callbacks and run 'prepare' callbacks 102 prepare_dispatcher 100 103 end 101 104 102 105 # Check for valid Ruby version … … 338 341 load(initializer) 339 342 end 340 343 end 344 345 def prepare_dispatcher 346 require 'dispatcher' unless defined?(::Dispatcher) 347 Dispatcher.define_dispatcher_callbacks(configuration.cache_classes) 348 Dispatcher.new(RAILS_DEFAULT_LOGGER).send :run_callbacks, :prepare 349 end 341 350 342 351 end 343 352