Class: ActionController::Dispatcher

Inherits:
Object
  • Object
show all
Includes:
ActiveSupport::Callbacks
Defined in:
lib/action_controller/dispatcher.rb

Overview

Dispatches requests to the appropriate controller and takes care of reloading the app after each request when Dependencies.load? is true.

Constant Summary collapse

@@guard =
Mutex.new

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(output = $stdout, request = nil, response = nil) ⇒ Dispatcher

Returns a new instance of Dispatcher.


105
106
107
# File 'lib/action_controller/dispatcher.rb', line 105

def initialize(output = $stdout, request = nil, response = nil)
  @output, @request, @response = output, request, response
end

Class Method Details

.define_dispatcher_callbacks(cache_classes) ⇒ Object


8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/action_controller/dispatcher.rb', line 8

def define_dispatcher_callbacks(cache_classes)
  unless cache_classes
    # Development mode callbacks
    before_dispatch :reload_application
    after_dispatch :cleanup_application

    ActionView::Helpers::AssetTagHelper.cache_asset_timestamps = false
  end

  # Common callbacks
  to_prepare :load_application_controller do
    begin
      require_dependency 'application' unless defined?(::ApplicationController)
    rescue LoadError => error
      raise unless error.message =~ /application\.rb/
    end
  end

  if defined?(ActiveRecord)
    after_dispatch :checkin_connections
    to_prepare(:activerecord_instantiate_observers) { ActiveRecord::Base.instantiate_observers }
  end

  after_dispatch :flush_logger if Base.logger && Base.logger.respond_to?(:flush)

  to_prepare do
    I18n.reload!
  end
end

.dispatch(cgi = nil, session_options = CgiRequest::DEFAULT_SESSION_OPTIONS, output = $stdout) ⇒ Object

Backward-compatible class method takes CGI-specific args. Deprecated in favor of Dispatcher.new(output, request, response).dispatch.


40
41
42
# File 'lib/action_controller/dispatcher.rb', line 40

def dispatch(cgi = nil, session_options = CgiRequest::DEFAULT_SESSION_OPTIONS, output = $stdout)
  new(output).dispatch_cgi(cgi, session_options)
end

.failsafe_response(fallback_output, status, originating_exception = nil) ⇒ Object

If the block raises, send status code as a last-ditch response.


59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/action_controller/dispatcher.rb', line 59

def failsafe_response(fallback_output, status, originating_exception = nil)
  yield
rescue Exception => exception
  begin
    log_failsafe_exception(status, originating_exception || exception)
    body = failsafe_response_body(status)
    fallback_output.write "Status: #{status}\r\nContent-Type: text/html\r\n\r\n#{body}"
    nil
  rescue Exception => failsafe_error # Logger or IO errors
    $stderr.puts "Error during failsafe response: #{failsafe_error}"
    $stderr.puts "(originally #{originating_exception})" if originating_exception
  end
end

.to_prepare(identifier = nil, &block) ⇒ Object

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.


52
53
54
55
56
# File 'lib/action_controller/dispatcher.rb', line 52

def to_prepare(identifier = nil, &block)
  @prepare_dispatch_callbacks ||= ActiveSupport::Callbacks::CallbackChain.new
  callback = ActiveSupport::Callbacks::Callback.new(:prepare_dispatch, block, :identifier => identifier)
  @prepare_dispatch_callbacks.replace_or_append!(callback)
end

Instance Method Details

#call(env) ⇒ Object


140
141
142
143
144
# File 'lib/action_controller/dispatcher.rb', line 140

def call(env)
  @request = RackRequest.new(env)
  @response = RackResponse.new(@request)
  dispatch
end

#checkin_connectionsObject


175
176
177
178
179
# File 'lib/action_controller/dispatcher.rb', line 175

def checkin_connections
  # Don't return connection (and peform implicit rollback) if this request is a part of integration test
  return if test_request?
  ActiveRecord::Base.clear_active_connections!
end

#cleanup_applicationObject

Cleanup the application by clearing out loaded classes so they can be reloaded on the next request without restarting the server.


156
157
158
159
160
# File 'lib/action_controller/dispatcher.rb', line 156

def cleanup_application
  ActiveRecord::Base.reset_subclasses if defined?(ActiveRecord)
  ActiveSupport::Dependencies.clear
  ActiveRecord::Base.clear_reloadable_connections! if defined?(ActiveRecord)
end

#dispatchObject


120
121
122
123
124
125
126
127
128
# File 'lib/action_controller/dispatcher.rb', line 120

def dispatch
  if ActionController::Base.allow_concurrency
    dispatch_unlocked
  else
    @@guard.synchronize do
      dispatch_unlocked
    end
  end
end

#dispatch_cgi(cgi, session_options) ⇒ Object


130
131
132
133
134
135
136
137
138
# File 'lib/action_controller/dispatcher.rb', line 130

def dispatch_cgi(cgi, session_options)
  if cgi ||= self.class.failsafe_response(@output, '400 Bad Request') { CGI.new }
    @request = CgiRequest.new(cgi, session_options)
    @response = CgiResponse.new(cgi)
    dispatch
  end
rescue Exception => exception
  failsafe_rescue exception
end

#dispatch_unlockedObject


109
110
111
112
113
114
115
116
117
118
# File 'lib/action_controller/dispatcher.rb', line 109

def dispatch_unlocked
  begin
    run_callbacks :before_dispatch
    handle_request
  rescue Exception => exception
    failsafe_rescue exception
  ensure
    run_callbacks :after_dispatch, :enumerator => :reverse_each
  end
end

#flush_loggerObject


162
163
164
# File 'lib/action_controller/dispatcher.rb', line 162

def flush_logger
  Base.logger.flush
end

#mark_as_test_request!Object


166
167
168
169
# File 'lib/action_controller/dispatcher.rb', line 166

def mark_as_test_request!
  @test_request = true
  self
end

#reload_applicationObject


146
147
148
149
150
151
152
# File 'lib/action_controller/dispatcher.rb', line 146

def reload_application
  # Run prepare callbacks before every request in development mode
  run_callbacks :prepare_dispatch

  Routing::Routes.reload
  ActionController::Base.view_paths.reload!
end

#test_request?Boolean

Returns:

  • (Boolean)

171
172
173
# File 'lib/action_controller/dispatcher.rb', line 171

def test_request?
  @test_request
end