提交 cbc3afb8 编写于 作者: N Nicholas Seckar

Add Dispatcher.to_prepare and config.to_prepare to provide a pre-request hook.

git-svn-id: http://svn-commit.rubyonrails.org/rails/trunk@4686 5ecf4fe2-1ee6-0310-87b1-e25e094e27de
上级 000a8ed9
*SVN*
* Add Dispatcher.to_prepare and config.to_prepare to provide a pre-request hook. [Nicholas Seckar]
* Tweak the Rails load order so observers are loaded after plugins, and reloaded in development mode. Closed #5279. [Rick Olson]
* Added that you can change the web server port in config/lighttpd.conf from script/server --port/-p #5465 [mats@imediatec.co.uk]
......
......@@ -25,6 +25,7 @@
# to the appropriate controller and action. It also takes care of resetting
# the environment (when Dependencies.load? is true) after each request.
class Dispatcher
class << self
# Dispatch the given CGI request, using the given session options, and
......@@ -54,11 +55,36 @@ def dispatch(cgi = nil, session_options = ActionController::CgiRequest::DEFAULT_
# to restart the server (WEBrick, FastCGI, etc.).
def reset_application!
Dependencies.clear
ActiveRecord::Base.reset
ActiveRecord::Base.reset if defined?(ActiveRecord)
Class.remove_class(*Reloadable.reloadable_classes)
end
# Add a preparation callback. Preparation callbacks are run before every
# request in development mode, and before the first request in production
# mode.
#
# An optional identifier may be supplied for the callback. If provided,
# to_prepare may be called again with the same identifier to replace the
# existing callback. Passing an identifier is a suggested practice if the
# code adding a preparation block may be reloaded.
def to_prepare(identifier = nil, &block)
unless identifier.nil?
callback = preparation_callbacks.detect { |ident, _| ident == identifier }
if callback # Already registered: update the existing callback
callback[-1] = block
return
end
end
preparation_callbacks << [identifier, block]
nil
end
private
attr_accessor :preparation_callbacks, :preparation_callbacks_run
alias_method :preparation_callbacks_run?, :preparation_callbacks_run
# CGI.new plus exception handling. CGI#read_multipart raises EOFError
# if body.empty? or body.size != Content-Length and raises ArgumentError
# if Content-Length is non-integer.
......@@ -67,10 +93,15 @@ def new_cgi(output)
end
def prepare_application
ActionController::Routing::Routes.reload if Dependencies.load?
if Dependencies.load?
ActionController::Routing::Routes.reload
self.preparation_callbacks_run = false
end
prepare_breakpoint
require_dependency('application.rb') unless Object.const_defined?(:ApplicationController)
ActiveRecord::Base.verify_active_connections!
ActiveRecord::Base.verify_active_connections! if defined?(ActiveRecord)
run_preparation_callbacks
end
def reset_after_dispatch
......@@ -87,6 +118,12 @@ def prepare_breakpoint
nil
end
def run_preparation_callbacks
return if preparation_callbacks_run?
preparation_callbacks.each { |_, callback| callback.call }
self.preparation_callbacks_run = true
end
# If the block raises, send status code as a last-ditch response.
def failsafe_response(output, status, exception = nil)
yield
......@@ -117,4 +154,8 @@ def failsafe_response(output, status, exception = nil)
end
end
end
self.preparation_callbacks = []
self.preparation_callbacks_run = false
end
......@@ -294,6 +294,13 @@ def after_initialize
configuration.after_initialize_block.call if configuration.after_initialize_block
end
# Add a preparation callback that will run before every request in development
# mode, or before the first request in production.
#
# See Dispatcher#to_prepare.
def to_prepare(&callback)
Dispatcher.to_prepare(&callback)
end
protected
# Return a list of plugin paths within base_path. A plugin path is
......
......@@ -24,6 +24,8 @@ class DispatcherTest < Test::Unit::TestCase
def setup
@output = StringIO.new
ENV['REQUEST_METHOD'] = "GET"
Dispatcher.send(:preparation_callbacks).clear
Dispatcher.send(:preparation_callbacks_run=, false)
end
def teardown
......@@ -84,6 +86,53 @@ def test_bad_multipart_request
ensure
$stdin = old_stdin
end
def test_preparation_callbacks
Object.const_set :ApplicationController, nil
old_mechanism = Dependencies.mechanism
a = b = c = nil
Dispatcher.to_prepare { a = b = c = 1 }
Dispatcher.to_prepare { b = c = 2 }
Dispatcher.to_prepare { c = 3 }
Dispatcher.send :prepare_application
assert_equal 1, a
assert_equal 2, b
assert_equal 3, c
# When mechanism is :load, perform the callbacks each request:
Dependencies.mechanism = :load
a = b = c = nil
Dispatcher.send :prepare_application
assert_equal 1, a
assert_equal 2, b
assert_equal 3, c
# But when not :load, make sure they are only run once
a = b = c = nil
Dependencies.mechanism = :not_load
Dispatcher.send :prepare_application
assert_equal nil, a || b || c
ensure
Dependencies.mechanism = old_mechanism
Object.send :remove_const, :ApplicationController
end
def test_to_prepare_with_identifier_replaces
Object.const_set :ApplicationController, nil
a = b = nil
Dispatcher.to_prepare(:unique_id) { a = b = 1 }
Dispatcher.to_prepare(:unique_id) { a = 2 }
Dispatcher.send :prepare_application
assert_equal 2, a
assert_equal nil, b
ensure
Object.send :remove_const, :ApplicationController
end
private
def dispatch
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册