aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_dispatch
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_dispatch')
-rw-r--r--actionpack/lib/action_dispatch/journey/router.rb1
-rw-r--r--actionpack/lib/action_dispatch/middleware/exception_wrapper.rb1
-rw-r--r--actionpack/lib/action_dispatch/middleware/request_id.rb12
-rw-r--r--actionpack/lib/action_dispatch/middleware/static.rb5
-rw-r--r--actionpack/lib/action_dispatch/routing/route_set.rb12
-rw-r--r--actionpack/lib/action_dispatch/routing/routes_proxy.rb9
-rw-r--r--actionpack/lib/action_dispatch/testing/assertions/routing.rb22
-rw-r--r--actionpack/lib/action_dispatch/testing/integration.rb90
8 files changed, 83 insertions, 69 deletions
diff --git a/actionpack/lib/action_dispatch/journey/router.rb b/actionpack/lib/action_dispatch/journey/router.rb
index 2b036796ab..e9df984c86 100644
--- a/actionpack/lib/action_dispatch/journey/router.rb
+++ b/actionpack/lib/action_dispatch/journey/router.rb
@@ -121,6 +121,7 @@ module ActionDispatch
end
def match_head_routes(routes, req)
+ routes.delete_if { |route| route.verb == // }
head_routes = match_routes(routes, req)
if head_routes.empty?
diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
index 5595a73887..d176a73633 100644
--- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
+++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
@@ -1,5 +1,6 @@
require 'action_controller/metal/exceptions'
require 'active_support/core_ext/module/attribute_accessors'
+require 'rack/utils'
module ActionDispatch
class ExceptionWrapper
diff --git a/actionpack/lib/action_dispatch/middleware/request_id.rb b/actionpack/lib/action_dispatch/middleware/request_id.rb
index 25658bac3d..cf31815c23 100644
--- a/actionpack/lib/action_dispatch/middleware/request_id.rb
+++ b/actionpack/lib/action_dispatch/middleware/request_id.rb
@@ -12,19 +12,23 @@ module ActionDispatch
# The unique request id can be used to trace a request end-to-end and would typically end up being part of log files
# from multiple pieces of the stack.
class RequestId
+ X_REQUEST_ID = "X-Request-Id".freeze # :nodoc:
+ ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id".freeze # :nodoc:
+ HTTP_X_REQUEST_ID = "HTTP_X_REQUEST_ID".freeze # :nodoc:
+
def initialize(app)
@app = app
end
def call(env)
- env["action_dispatch.request_id"] = external_request_id(env) || internal_request_id
- @app.call(env).tap { |_status, headers, _body| headers["X-Request-Id"] = env["action_dispatch.request_id"] }
+ env[ACTION_DISPATCH_REQUEST_ID] = external_request_id(env) || internal_request_id
+ @app.call(env).tap { |_status, headers, _body| headers[X_REQUEST_ID] = env[ACTION_DISPATCH_REQUEST_ID] }
end
private
def external_request_id(env)
- if request_id = env["HTTP_X_REQUEST_ID"].presence
- request_id.gsub(/[^\w\-]/, "").first(255)
+ if request_id = env[HTTP_X_REQUEST_ID].presence
+ request_id.gsub(/[^\w\-]/, "".freeze).first(255)
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb
index 002bf8b11a..2e1bd45c3d 100644
--- a/actionpack/lib/action_dispatch/middleware/static.rb
+++ b/actionpack/lib/action_dispatch/middleware/static.rb
@@ -23,10 +23,9 @@ module ActionDispatch
def match?(path)
path = URI.parser.unescape(path)
return false unless path.valid_encoding?
+ path = Rack::Utils.clean_path_info path
- paths = [path, "#{path}#{ext}", "#{path}/index#{ext}"].map { |v|
- Rack::Utils.clean_path_info v
- }
+ paths = [path, "#{path}#{ext}", "#{path}/index#{ext}"]
if match = paths.detect { |p|
path = File.join(@root, p)
diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb
index 948cbdc014..ce04f0b08a 100644
--- a/actionpack/lib/action_dispatch/routing/route_set.rb
+++ b/actionpack/lib/action_dispatch/routing/route_set.rb
@@ -395,9 +395,11 @@ module ActionDispatch
return if MountedHelpers.method_defined?(name)
routes = self
+ helpers = routes.url_helpers
+
MountedHelpers.class_eval do
define_method "_#{name}" do
- RoutesProxy.new(routes, _routes_context)
+ RoutesProxy.new(routes, _routes_context, helpers)
end
end
@@ -409,14 +411,6 @@ module ActionDispatch
end
def url_helpers(supports_path = true)
- if supports_path
- @url_helpers_with_paths ||= generate_url_helpers(supports_path)
- else
- @url_helpers_without_paths ||= generate_url_helpers(supports_path)
- end
- end
-
- def generate_url_helpers(supports_path)
routes = self
Module.new do
diff --git a/actionpack/lib/action_dispatch/routing/routes_proxy.rb b/actionpack/lib/action_dispatch/routing/routes_proxy.rb
index e2393d3799..040ea04046 100644
--- a/actionpack/lib/action_dispatch/routing/routes_proxy.rb
+++ b/actionpack/lib/action_dispatch/routing/routes_proxy.rb
@@ -8,8 +8,9 @@ module ActionDispatch
attr_accessor :scope, :routes
alias :_routes :routes
- def initialize(routes, scope)
+ def initialize(routes, scope, helpers)
@routes, @scope = routes, scope
+ @helpers = helpers
end
def url_options
@@ -19,16 +20,16 @@ module ActionDispatch
end
def respond_to?(method, include_private = false)
- super || routes.url_helpers.respond_to?(method)
+ super || @helpers.respond_to?(method)
end
def method_missing(method, *args)
- if routes.url_helpers.respond_to?(method)
+ if @helpers.respond_to?(method)
self.class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{method}(*args)
options = args.extract_options!
args << url_options.merge((options || {}).symbolize_keys)
- routes.url_helpers.#{method}(*args)
+ @helpers.#{method}(*args)
end
RUBY
send(method, *args)
diff --git a/actionpack/lib/action_dispatch/testing/assertions/routing.rb b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
index a927738b42..c94eea9134 100644
--- a/actionpack/lib/action_dispatch/testing/assertions/routing.rb
+++ b/actionpack/lib/action_dispatch/testing/assertions/routing.rb
@@ -38,18 +38,24 @@ module ActionDispatch
# # Test a custom route
# assert_recognizes({controller: 'items', action: 'show', id: '1'}, 'view/item1')
def assert_recognizes(expected_options, path, extras={}, msg=nil)
- request = recognized_request_for(path, extras, msg)
+ if path.is_a?(Hash) && path[:method].to_s == "all"
+ [:get, :post, :put, :delete].each do |method|
+ assert_recognizes(expected_options, path.merge(method: method), extras, msg)
+ end
+ else
+ request = recognized_request_for(path, extras, msg)
- expected_options = expected_options.clone
+ expected_options = expected_options.clone
- expected_options.stringify_keys!
+ expected_options.stringify_keys!
- msg = message(msg, "") {
- sprintf("The recognized options <%s> did not match <%s>, difference:",
- request.path_parameters, expected_options)
- }
+ msg = message(msg, "") {
+ sprintf("The recognized options <%s> did not match <%s>, difference:",
+ request.path_parameters, expected_options)
+ }
- assert_equal(expected_options, request.path_parameters, msg)
+ assert_equal(expected_options, request.path_parameters, msg)
+ end
end
# Asserts that the provided options can be used to generate the provided path. This is the inverse of +assert_recognizes+.
diff --git a/actionpack/lib/action_dispatch/testing/integration.rb b/actionpack/lib/action_dispatch/testing/integration.rb
index db6233840a..9b00616968 100644
--- a/actionpack/lib/action_dispatch/testing/integration.rb
+++ b/actionpack/lib/action_dispatch/testing/integration.rb
@@ -92,11 +92,12 @@ module ActionDispatch
end
end
- headers ||= {}
- headers.merge!(env) if env
- headers['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
- headers['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
- process(request_method, path, params: params, headers: headers)
+ ActiveSupport::Deprecation.warn(<<-MSG.strip_heredoc)
+ xhr and xml_http_request methods are deprecated in favor of
+ `get "/posts", xhr: true` and `post "/posts/1", xhr: true`
+ MSG
+
+ process(request_method, path, params: params, headers: headers, xhr: true)
end
alias xhr :xml_http_request
@@ -221,15 +222,6 @@ module ActionDispatch
super()
@app = app
- # If the app is a Rails app, make url_helpers available on the session
- # This makes app.url_for and app.foo_path available in the console
- if app.respond_to?(:routes)
- singleton_class.class_eval do
- include app.routes.url_helpers
- include app.routes.mounted_helpers
- end
- end
-
reset!
end
@@ -306,30 +298,29 @@ module ActionDispatch
end
end
- REQUEST_KWARGS = %i(params headers env)
+ REQUEST_KWARGS = %i(params headers env xhr)
def kwarg_request?(*args)
args[0].respond_to?(:keys) && args[0].keys.any? { |k| REQUEST_KWARGS.include?(k) }
end
def non_kwarg_request_warning
ActiveSupport::Deprecation.warn(<<-MSG.strip_heredoc)
- ActionDispatch::Integration::TestCase HTTP request methods will accept only
- keyword arguments in future Rails versions.
+ ActionDispatch::IntegrationTest HTTP request methods will accept only
+ the following keyword arguments in future Rails versions:
+ #{REQUEST_KWARGS.join(', ')}
Examples:
get '/profile',
params: { id: 1 },
headers: { 'X-Extra-Header' => '123' },
- env: { 'action_dispatch.custom' => 'custom' }
-
- xhr :post, '/profile',
- params: { id: 1 }
+ env: { 'action_dispatch.custom' => 'custom' },
+ xhr: true
MSG
end
# Performs the actual request.
- def process(method, path, params: nil, headers: nil, env: nil)
+ def process(method, path, params: nil, headers: nil, env: nil, xhr: false)
if path =~ %r{://}
location = URI.parse(path)
https! URI::HTTPS === location if location.scheme
@@ -354,6 +345,13 @@ module ActionDispatch
"CONTENT_TYPE" => "application/x-www-form-urlencoded",
"HTTP_ACCEPT" => accept
}
+
+ if xhr
+ headers ||= {}
+ headers['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest'
+ headers['HTTP_ACCEPT'] ||= [Mime::JS, Mime::HTML, Mime::XML, 'text/xml', Mime::ALL].join(', ')
+ end
+
# this modifies the passed request_env directly
if headers.present?
Http::Headers.new(request_env).merge!(headers)
@@ -377,7 +375,7 @@ module ActionDispatch
@controller = session.last_request.env['action_controller.instance']
- return response.status
+ response.status
end
def build_full_uri(path, env)
@@ -388,14 +386,36 @@ module ActionDispatch
module Runner
include ActionDispatch::Assertions
- def app
- @app ||= nil
+ APP_SESSIONS = {}
+
+ attr_reader :app
+
+ def before_setup
+ super
+ @app = nil
+ @integration_session = nil
+ end
+
+ def integration_session
+ @integration_session ||= create_session(app)
end
# Reset the current session. This is useful for testing multiple sessions
# in a single test case.
def reset!
- @integration_session = Integration::Session.new(app)
+ @integration_session = create_session(app)
+ end
+
+ def create_session(app)
+ klass = APP_SESSIONS[app] ||= Class.new(Integration::Session) {
+ # If the app is a Rails app, make url_helpers available on the session
+ # This makes app.url_for and app.foo_path available in the console
+ if app.respond_to?(:routes)
+ include app.routes.url_helpers
+ include app.routes.mounted_helpers
+ end
+ }
+ klass.new(app)
end
def remove! # :nodoc:
@@ -405,8 +425,6 @@ module ActionDispatch
%w(get post patch put head delete cookies assigns
xml_http_request xhr get_via_redirect post_via_redirect).each do |method|
define_method(method) do |*args|
- reset! unless integration_session
-
# reset the html_document variable, except for cookies/assigns calls
unless method == 'cookies' || method == 'assigns'
@html_document = nil
@@ -438,19 +456,16 @@ module ActionDispatch
# Copy the instance variables from the current session instance into the
# test instance.
def copy_session_variables! #:nodoc:
- return unless integration_session
- %w(controller response request).each do |var|
- instance_variable_set("@#{var}", @integration_session.__send__(var))
- end
+ @controller = @integration_session.controller
+ @response = @integration_session.response
+ @request = @integration_session.request
end
def default_url_options
- reset! unless integration_session
integration_session.default_url_options
end
def default_url_options=(options)
- reset! unless integration_session
integration_session.default_url_options = options
end
@@ -460,7 +475,6 @@ module ActionDispatch
# Delegate unhandled messages to the current session instance.
def method_missing(sym, *args, &block)
- reset! unless integration_session
if integration_session.respond_to?(sym)
integration_session.__send__(sym, *args, &block).tap do
copy_session_variables!
@@ -469,11 +483,6 @@ module ActionDispatch
super
end
end
-
- private
- def integration_session
- @integration_session ||= nil
- end
end
end
@@ -650,7 +659,6 @@ module ActionDispatch
end
def url_options
- reset! unless integration_session
integration_session.url_options
end