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.



103
104
105
# File 'lib/action_controller/dispatcher.rb', line 103

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
# 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
  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.



38
39
40
# File 'lib/action_controller/dispatcher.rb', line 38

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.



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

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.



50
51
52
53
54
# File 'lib/action_controller/dispatcher.rb', line 50

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



138
139
140
141
142
# File 'lib/action_controller/dispatcher.rb', line 138

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

#checkin_connectionsObject



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

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.



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

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

#dispatchObject



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

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

#dispatch_cgi(cgi, session_options) ⇒ Object



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

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



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

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



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

def flush_logger
  Base.logger.flush
end

#mark_as_test_request!Object



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

def mark_as_test_request!
  @test_request = true
  self
end

#reload_applicationObject



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

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

  Routing::Routes.reload
  ActionController::Base.view_paths.reload!
  ActionView::Helpers::AssetTagHelper::AssetTag::Cache.clear
end

#test_request?Boolean

Returns:

  • (Boolean)


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

def test_request?
  @test_request
end