aboutsummaryrefslogtreecommitdiffstats
path: root/railties
diff options
context:
space:
mode:
authorNicholas Seckar <nseckar@gmail.com>2006-08-06 02:51:53 +0000
committerNicholas Seckar <nseckar@gmail.com>2006-08-06 02:51:53 +0000
commitcbc3afb8786a9e6caa486fa2c97b17348c9eff51 (patch)
tree949c86a1371ea2d3aff00af4398581c4cf6f00cd /railties
parent000a8ed9c688afe167f1d4cd4b6327d350272444 (diff)
downloadrails-cbc3afb8786a9e6caa486fa2c97b17348c9eff51.tar.gz
rails-cbc3afb8786a9e6caa486fa2c97b17348c9eff51.tar.bz2
rails-cbc3afb8786a9e6caa486fa2c97b17348c9eff51.zip
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
Diffstat (limited to 'railties')
-rw-r--r--railties/CHANGELOG2
-rw-r--r--railties/lib/dispatcher.rb47
-rw-r--r--railties/lib/initializer.rb7
-rw-r--r--railties/test/dispatcher_test.rb49
4 files changed, 102 insertions, 3 deletions
diff --git a/railties/CHANGELOG b/railties/CHANGELOG
index 63f3197fcd..74ce8c0a3a 100644
--- a/railties/CHANGELOG
+++ b/railties/CHANGELOG
@@ -1,5 +1,7 @@
*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]
diff --git a/railties/lib/dispatcher.rb b/railties/lib/dispatcher.rb
index 32f286434f..a125018446 100644
--- a/railties/lib/dispatcher.rb
+++ b/railties/lib/dispatcher.rb
@@ -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 @@ class Dispatcher
# 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 @@ class Dispatcher
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 @@ class Dispatcher
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 @@ class Dispatcher
end
end
end
+
+ self.preparation_callbacks = []
+ self.preparation_callbacks_run = false
+
end
diff --git a/railties/lib/initializer.rb b/railties/lib/initializer.rb
index de58051f97..d18a5ecc4d 100644
--- a/railties/lib/initializer.rb
+++ b/railties/lib/initializer.rb
@@ -294,6 +294,13 @@ module Rails
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
diff --git a/railties/test/dispatcher_test.rb b/railties/test/dispatcher_test.rb
index 41d08e224e..8fb19b173a 100644
--- a/railties/test/dispatcher_test.rb
+++ b/railties/test/dispatcher_test.rb
@@ -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 @@ class DispatcherTest < Test::Unit::TestCase
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