提交 8c8942ed 编写于 作者: J José Valim

Move Dispatcher setup to Railties and add instrumentation hook.

上级 5a8e7287
......@@ -39,7 +39,7 @@ module ActionController
autoload :Verification
end
autoload :Dispatcher, 'action_controller/dispatch/dispatcher'
autoload :Dispatcher, 'action_controller/deprecated/dispatcher'
autoload :Integration, 'action_controller/deprecated/integration_test'
autoload :IntegrationTest, 'action_controller/deprecated/integration_test'
autoload :PerformanceTest, 'action_controller/deprecated/performance_test'
......
module ActionController
class Dispatcher
cattr_accessor :prepare_each_request
self.prepare_each_request = false
class << self
def before_dispatch(*args, &block)
ActiveSupport::Deprecation.warn "ActionController::Dispatcher.before_dispatch is deprecated. " <<
"Please use ActionDispatch::Callbacks.before instead.", caller
ActionDispatch::Callbacks.before(*args, &block)
end
def after_dispatch(*args, &block)
ActiveSupport::Deprecation.warn "ActionController::Dispatcher.after_dispatch is deprecated. " <<
"Please use ActionDispatch::Callbacks.after instead.", caller
ActionDispatch::Callbacks.after(*args, &block)
end
def to_prepare(*args, &block)
ActiveSupport::Deprecation.warn "ActionController::Dispatcher.to_prepare is deprecated. " <<
"Please use ActionDispatch::Callbacks.to_prepare instead.", caller
ActionDispatch::Callbacks.after(*args, &block)
end
def new
ActiveSupport::Deprecation.warn "ActionController::Dispatcher.new is deprecated, use Rails.application instead."
Rails.application
end
end
end
end
require 'active_support/core_ext/module/delegation'
module ActionController
# Dispatches requests to the appropriate controller and takes care of
# reloading the app after each request when Dependencies.load? is true.
class Dispatcher
cattr_accessor :prepare_each_request
self.prepare_each_request = false
class << self
def define_dispatcher_callbacks(cache_classes)
unless cache_classes
# Run prepare callbacks before every request in development mode
self.prepare_each_request = true
ActionDispatch::Callbacks.after_dispatch do
# Cleanup the application before processing the current request.
ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
ActiveSupport::Dependencies.clear
ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
end
ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false
end
if defined?(ActiveRecord)
to_prepare(:activerecord_instantiate_observers) do
ActiveRecord::Base.instantiate_observers
end
end
if Base.logger && Base.logger.respond_to?(:flush)
after_dispatch do
Base.logger.flush
end
end
to_prepare do
I18n.reload!
end
end
delegate :to_prepare, :before_dispatch, :around_dispatch, :after_dispatch,
:to => ActionDispatch::Callbacks
def new
# DEPRECATE Rails application fallback
Rails.application
end
end
end
end
......@@ -66,7 +66,7 @@ def cleanup_view_runtime #:nodoc:
module ClassMethods
# A hook which allows other frameworks to log what happened during
# controller process action. This method should return an awway
# controller process action. This method should return an array
# with the messages to be added.
# :api: plugin
def log_process_action(controller) #:nodoc:
......
......@@ -69,12 +69,12 @@ def name
app.config.middleware.insert_before(:"ActionDispatch::ParamsParser", middleware)
end
# # Prepare dispatcher callbacks and run 'prepare' callbacks
# Prepare dispatcher callbacks and run 'prepare' callbacks
initializer "action_controller.prepare_dispatcher" do |app|
# TODO: This used to say unless defined?(Dispatcher). Find out why and fix.
# Notice that at this point, ActionDispatch::Callbacks were already loaded.
require 'rails/dispatcher'
Dispatcher.define_dispatcher_callbacks(app.config.cache_classes)
ActionController::Dispatcher.prepare_each_request = true unless app.config.cache_classes
unless app.config.cache_classes
# Setup dev mode route reloading
......@@ -85,7 +85,7 @@ def name
app.reload_routes!
end
end
ActionDispatch::Callbacks.before_dispatch { |callbacks| reload_routes.call }
ActionDispatch::Callbacks.before { |callbacks| reload_routes.call }
end
end
......
module ActionDispatch
# Provide callbacks to be executed before and after the request dispatch.
#
# It also provides a to_prepare callback, which is performed in all requests
# in development by only once in production and notification callback for async
# operations.
#
class Callbacks
include ActiveSupport::Callbacks
......@@ -29,12 +35,6 @@ def self.after(*args, &block)
set_callback(:call, :after, *args, &block)
end
class << self
# DEPRECATED
alias_method :before_dispatch, :before
alias_method :after_dispatch, :after
end
def initialize(app, prepare_each_request = false)
@app, @prepare_each_request = app, prepare_each_request
run_callbacks(:prepare)
......@@ -43,7 +43,10 @@ def initialize(app, prepare_each_request = false)
def call(env)
run_callbacks(:call) do
run_callbacks(:prepare) if @prepare_each_request
@app.call(env)
ActiveSupport::Notifications.instrument "action_dispatch.callback" do
@app.call(env)
end
end
end
end
......
......@@ -1080,7 +1080,7 @@ def error_messages(options = {})
# Add the submit button for the given form. When no value is given, it checks
# if the object is a new resource or not to create the proper label:
#
# <% form_for @post do %>
# <% form_for @post do |f| %>
# <%= f.submit %>
# <% end %>
#
......
......@@ -7,5 +7,11 @@ class Railtie < Rails::Railtie
require "action_view/railties/subscriber"
subscriber ActionView::Railties::Subscriber.new
initializer "action_view.cache_asset_timestamps" do |app|
unless app.config.cache_classes
ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false
end
end
end
end
\ No newline at end of file
require 'abstract_unit'
class DispatcherTest < Test::Unit::TestCase
Dispatcher = ActionController::Dispatcher
class Foo
cattr_accessor :a, :b
end
# Ensure deprecated dispatcher works
class DeprecatedDispatcherTest < ActiveSupport::TestCase
class DummyApp
def call(env)
[200, {}, 'response']
end
end
def setup
ENV['REQUEST_METHOD'] = 'GET'
# Clear callbacks as they are redefined by Dispatcher#define_dispatcher_callbacks
ActionDispatch::Callbacks.reset_callbacks(:prepare)
ActionDispatch::Callbacks.reset_callbacks(:call)
ActionController::Routing::Routes.stubs(:call).returns([200, {}, 'response'])
Dispatcher.stubs(:require_dependency)
end
def teardown
ENV.delete 'REQUEST_METHOD'
end
def test_assert_deprecated_to_prepare
a = nil
assert_deprecated do
ActionController::Dispatcher.to_prepare { a = 1 }
end
def test_clears_dependencies_after_dispatch_if_in_loading_mode
ActiveSupport::Dependencies.expects(:clear).once
dispatch(false)
assert_nil a
dispatch
assert_equal 1, a
end
def test_prepare_callbacks
a = b = c = nil
ActionDispatch::Callbacks.to_prepare { |*args| a = b = c = 1 }
ActionDispatch::Callbacks.to_prepare { |*args| b = c = 2 }
ActionDispatch::Callbacks.to_prepare { |*args| c = 3 }
def test_assert_deprecated_before_dispatch
a = nil
# Ensure to_prepare callbacks are not run when defined
assert_nil a || b || c
assert_deprecated do
ActionController::Dispatcher.before_dispatch { a = 1 }
end
# Run callbacks
assert_nil a
dispatch
assert_equal 1, a
assert_equal 2, b
assert_equal 3, c
# Make sure they are only run once
a = b = c = nil
dispatch
assert_nil a || b || c
end
def test_to_prepare_with_identifier_replaces
ActionDispatch::Callbacks.to_prepare(:unique_id) { |*args| Foo.a, Foo.b = 1, 1 }
ActionDispatch::Callbacks.to_prepare(:unique_id) { |*args| Foo.a = 2 }
def test_assert_deprecated_after_dispatch
a = nil
assert_deprecated do
ActionController::Dispatcher.after_dispatch { a = 1 }
end
assert_nil a
dispatch
assert_equal 2, Foo.a
assert_equal nil, Foo.b
assert_equal 1, a
end
private
def dispatch(cache_classes = true)
ActionController::Dispatcher.prepare_each_request = false
Dispatcher.define_dispatcher_callbacks(cache_classes)
@dispatcher ||= ActionDispatch::Callbacks.new(ActionController::Routing::Routes)
@dispatcher.call({'rack.input' => StringIO.new(''), 'action_dispatch.show_exceptions' => false})
def dispatch(cache_classes = true)
@dispatcher ||= ActionDispatch::Callbacks.new(DummyApp.new, !cache_classes)
@dispatcher.call({'rack.input' => StringIO.new('')})
end
def assert_subclasses(howmany, klass, message = klass.subclasses.inspect)
assert_equal howmany, klass.subclasses.size, message
end
end
require 'abstract_unit'
class DispatcherTest < Test::Unit::TestCase
class Foo
cattr_accessor :a, :b
end
class DummyApp
def call(env)
[200, {}, 'response']
end
end
def setup
Foo.a, Foo.b = 0, 0
ActionDispatch::Callbacks.reset_callbacks(:prepare)
ActionDispatch::Callbacks.reset_callbacks(:call)
end
def test_prepare_callbacks
a = b = c = nil
ActionDispatch::Callbacks.to_prepare { |*args| a = b = c = 1 }
ActionDispatch::Callbacks.to_prepare { |*args| b = c = 2 }
ActionDispatch::Callbacks.to_prepare { |*args| c = 3 }
# Ensure to_prepare callbacks are not run when defined
assert_nil a || b || c
# Run callbacks
dispatch
assert_equal 1, a
assert_equal 2, b
assert_equal 3, c
# Make sure they are only run once
a = b = c = nil
dispatch
assert_nil a || b || c
end
def test_to_prepare_with_identifier_replaces
ActionDispatch::Callbacks.to_prepare(:unique_id) { |*args| Foo.a, Foo.b = 1, 1 }
ActionDispatch::Callbacks.to_prepare(:unique_id) { |*args| Foo.a = 2 }
dispatch
assert_equal 2, Foo.a
assert_equal 0, Foo.b
end
def test_before_and_after_callbacks
ActionDispatch::Callbacks.before { |*args| Foo.a += 1; Foo.b += 1 }
ActionDispatch::Callbacks.after { |*args| Foo.a += 1; Foo.b += 1 }
dispatch
assert_equal 2, Foo.a
assert_equal 2, Foo.b
dispatch
assert_equal 4, Foo.a
assert_equal 4, Foo.b
end
def test_should_send_an_instrumentation_callback_for_async_processing
ActiveSupport::Notifications.expects(:instrument).with("action_dispatch.callback")
dispatch
end
private
def dispatch(cache_classes = true)
@dispatcher ||= ActionDispatch::Callbacks.new(DummyApp.new, !cache_classes)
@dispatcher.call({'rack.input' => StringIO.new('')})
end
end
......@@ -56,6 +56,19 @@ class Railtie < Rails::Railtie
initializer "active_record.load_observers" do
ActiveRecord::Base.instantiate_observers
ActionDispatch::Callbacks.to_prepare(:activerecord_instantiate_observers) do
ActiveRecord::Base.instantiate_observers
end
end
initializer "active_record.set_dispatch_hooks", :before => :set_clear_dependencies_hook do |app|
unless app.config.cache_classes
ActionDispatch::Callbacks.after do
ActiveRecord::Base.reset_subclasses
ActiveRecord::Base.clear_reloadable_connections!
end
end
end
# TODO: ActiveRecord::Base.logger should delegate to its own config.logger
......
......@@ -80,10 +80,7 @@ def initialize(application)
end
end
# Sets the logger for Active Record, Action Controller, and Action Mailer
# (but only for those frameworks that are to be loaded). If the framework's
# logger is already set, it is not changed, otherwise it is set to use
# RAILS_DEFAULT_LOGGER.
# Sets the logger for dependencies and cache store.
initializer :initialize_framework_logging do
ActiveSupport::Dependencies.logger ||= Rails.logger
Rails.cache.logger ||= Rails.logger
......@@ -99,7 +96,7 @@ def initialize(application)
# Loads support for "whiny nil" (noisy warnings when methods are invoked
# on +nil+ values) if Configuration#whiny_nils is true.
initializer :initialize_whiny_nils do
require('active_support/whiny_nil') if config.whiny_nils
require 'active_support/whiny_nil' if config.whiny_nils
end
# Sets the default value for Time.zone
......@@ -120,6 +117,8 @@ def initialize(application)
# Set the i18n configuration from config.i18n but special-case for the load_path which should be
# appended to what's already set instead of overwritten.
initializer :initialize_i18n do
require 'active_support/i18n'
config.i18n.each do |setting, value|
if setting == :load_path
I18n.load_path += value
......@@ -127,6 +126,18 @@ def initialize(application)
I18n.send("#{setting}=", value)
end
end
ActionDispatch::Callbacks.to_prepare do
I18n.reload!
end
end
initializer :set_clear_dependencies_hook do
unless config.cache_classes
ActionDispatch::Callbacks.after do
ActiveSupport::Dependencies.clear
end
end
end
initializer :initialize_notifications do
......
......@@ -20,5 +20,5 @@
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#++
require 'action_controller/dispatch/dispatcher'
require 'action_controller/deprecated/dispatcher'
Dispatcher = ActionController::Dispatcher
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册