actionpack 7.2.3 → 8.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +394 -119
- data/lib/abstract_controller/asset_paths.rb +4 -2
- data/lib/abstract_controller/base.rb +11 -5
- data/lib/abstract_controller/caching.rb +6 -3
- data/lib/abstract_controller/callbacks.rb +6 -0
- data/lib/abstract_controller/logger.rb +2 -1
- data/lib/abstract_controller/rendering.rb +0 -1
- data/lib/action_controller/api.rb +1 -0
- data/lib/action_controller/base.rb +3 -2
- data/lib/action_controller/caching.rb +1 -2
- data/lib/action_controller/form_builder.rb +4 -4
- data/lib/action_controller/log_subscriber.rb +22 -3
- data/lib/action_controller/metal/allow_browser.rb +12 -2
- data/lib/action_controller/metal/conditional_get.rb +30 -1
- data/lib/action_controller/metal/data_streaming.rb +5 -5
- data/lib/action_controller/metal/exceptions.rb +5 -0
- data/lib/action_controller/metal/flash.rb +1 -4
- data/lib/action_controller/metal/head.rb +3 -1
- data/lib/action_controller/metal/instrumentation.rb +1 -2
- data/lib/action_controller/metal/live.rb +65 -25
- data/lib/action_controller/metal/permissions_policy.rb +9 -0
- data/lib/action_controller/metal/rate_limiting.rb +39 -9
- data/lib/action_controller/metal/redirecting.rb +105 -13
- data/lib/action_controller/metal/renderers.rb +29 -9
- data/lib/action_controller/metal/rendering.rb +7 -1
- data/lib/action_controller/metal/request_forgery_protection.rb +18 -10
- data/lib/action_controller/metal/rescue.rb +9 -0
- data/lib/action_controller/metal/streaming.rb +5 -84
- data/lib/action_controller/metal/strong_parameters.rb +277 -89
- data/lib/action_controller/railtie.rb +33 -15
- data/lib/action_controller/structured_event_subscriber.rb +116 -0
- data/lib/action_controller/test_case.rb +12 -2
- data/lib/action_dispatch/http/cache.rb +138 -11
- data/lib/action_dispatch/http/content_security_policy.rb +14 -1
- data/lib/action_dispatch/http/filter_parameters.rb +5 -3
- data/lib/action_dispatch/http/mime_negotiation.rb +55 -1
- data/lib/action_dispatch/http/mime_types.rb +1 -0
- data/lib/action_dispatch/http/param_builder.rb +187 -0
- data/lib/action_dispatch/http/param_error.rb +26 -0
- data/lib/action_dispatch/http/parameters.rb +3 -3
- data/lib/action_dispatch/http/permissions_policy.rb +6 -0
- data/lib/action_dispatch/http/query_parser.rb +55 -0
- data/lib/action_dispatch/http/request.rb +70 -21
- data/lib/action_dispatch/http/response.rb +50 -16
- data/lib/action_dispatch/http/url.rb +110 -14
- data/lib/action_dispatch/journey/gtg/simulator.rb +33 -12
- data/lib/action_dispatch/journey/gtg/transition_table.rb +33 -41
- data/lib/action_dispatch/journey/nodes/node.rb +2 -1
- data/lib/action_dispatch/journey/parser.rb +99 -196
- data/lib/action_dispatch/journey/route.rb +45 -31
- data/lib/action_dispatch/journey/router/utils.rb +8 -14
- data/lib/action_dispatch/journey/router.rb +59 -81
- data/lib/action_dispatch/journey/routes.rb +7 -0
- data/lib/action_dispatch/journey/scanner.rb +44 -42
- data/lib/action_dispatch/journey/visitors.rb +55 -23
- data/lib/action_dispatch/journey/visualizer/fsm.js +4 -6
- data/lib/action_dispatch/log_subscriber.rb +7 -3
- data/lib/action_dispatch/middleware/cookies.rb +8 -4
- data/lib/action_dispatch/middleware/debug_exceptions.rb +24 -5
- data/lib/action_dispatch/middleware/debug_view.rb +11 -5
- data/lib/action_dispatch/middleware/exception_wrapper.rb +11 -11
- data/lib/action_dispatch/middleware/executor.rb +12 -2
- data/lib/action_dispatch/middleware/public_exceptions.rb +1 -5
- data/lib/action_dispatch/middleware/remote_ip.rb +11 -5
- data/lib/action_dispatch/middleware/request_id.rb +2 -1
- data/lib/action_dispatch/middleware/session/cache_store.rb +17 -0
- data/lib/action_dispatch/middleware/ssl.rb +13 -3
- data/lib/action_dispatch/middleware/templates/rescues/_copy_button.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +3 -5
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +9 -5
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +50 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -0
- data/lib/action_dispatch/railtie.rb +21 -0
- data/lib/action_dispatch/request/session.rb +1 -0
- data/lib/action_dispatch/request/utils.rb +9 -3
- data/lib/action_dispatch/routing/inspector.rb +80 -57
- data/lib/action_dispatch/routing/mapper.rb +404 -223
- data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -2
- data/lib/action_dispatch/routing/redirection.rb +10 -7
- data/lib/action_dispatch/routing/route_set.rb +21 -12
- data/lib/action_dispatch/routing/routes_proxy.rb +1 -0
- data/lib/action_dispatch/structured_event_subscriber.rb +20 -0
- data/lib/action_dispatch/system_test_case.rb +3 -3
- data/lib/action_dispatch/system_testing/browser.rb +12 -21
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +2 -2
- data/lib/action_dispatch/testing/assertions/response.rb +26 -2
- data/lib/action_dispatch/testing/assertions/routing.rb +27 -15
- data/lib/action_dispatch/testing/integration.rb +18 -7
- data/lib/action_dispatch.rb +14 -4
- data/lib/action_pack/gem_version.rb +2 -2
- metadata +18 -48
- data/lib/action_dispatch/journey/parser.y +0 -50
- data/lib/action_dispatch/journey/parser_extras.rb +0 -33
|
@@ -31,7 +31,7 @@ module ActionDispatch
|
|
|
31
31
|
# * `url_for`, so you can use it with a record as the argument, e.g.
|
|
32
32
|
# `url_for(@article)`;
|
|
33
33
|
# * ActionView::Helpers::FormHelper uses `polymorphic_path`, so you can write
|
|
34
|
-
# `
|
|
34
|
+
# `form_with(model: @article)` without having to specify `:url` parameter for the
|
|
35
35
|
# form action;
|
|
36
36
|
# * `redirect_to` (which, in fact, uses `url_for`) so you can write
|
|
37
37
|
# `redirect_to(post)` in your controllers;
|
|
@@ -61,7 +61,7 @@ module ActionDispatch
|
|
|
61
61
|
# argument to the method. For example:
|
|
62
62
|
#
|
|
63
63
|
# polymorphic_url([blog, @post]) # calls blog.post_path(@post)
|
|
64
|
-
#
|
|
64
|
+
# form_with(model: [blog, @post]) # => "/blog/posts/1"
|
|
65
65
|
#
|
|
66
66
|
module PolymorphicRoutes
|
|
67
67
|
# Constructs a call to a named RESTful route for the given record and returns
|
|
@@ -12,9 +12,10 @@ module ActionDispatch
|
|
|
12
12
|
class Redirect < Endpoint # :nodoc:
|
|
13
13
|
attr_reader :status, :block
|
|
14
14
|
|
|
15
|
-
def initialize(status, block)
|
|
15
|
+
def initialize(status, block, source_location)
|
|
16
16
|
@status = status
|
|
17
17
|
@block = block
|
|
18
|
+
@source_location = source_location
|
|
18
19
|
end
|
|
19
20
|
|
|
20
21
|
def redirect?; true; end
|
|
@@ -27,6 +28,7 @@ module ActionDispatch
|
|
|
27
28
|
payload[:status] = @status
|
|
28
29
|
payload[:location] = response.headers["Location"]
|
|
29
30
|
payload[:request] = request
|
|
31
|
+
payload[:source_location] = @source_location if @source_location
|
|
30
32
|
|
|
31
33
|
response.to_a
|
|
32
34
|
end
|
|
@@ -202,16 +204,17 @@ module ActionDispatch
|
|
|
202
204
|
# get 'accounts/:name' => redirect(SubdomainRedirector.new('api'))
|
|
203
205
|
#
|
|
204
206
|
def redirect(*args, &block)
|
|
205
|
-
options
|
|
206
|
-
status
|
|
207
|
-
path
|
|
207
|
+
options = args.extract_options!
|
|
208
|
+
status = options.delete(:status) || 301
|
|
209
|
+
path = args.shift
|
|
210
|
+
source_location = caller[0] if ActionDispatch.verbose_redirect_logs
|
|
208
211
|
|
|
209
|
-
return OptionRedirect.new(status, options) if options.any?
|
|
210
|
-
return PathRedirect.new(status, path) if String === path
|
|
212
|
+
return OptionRedirect.new(status, options, source_location) if options.any?
|
|
213
|
+
return PathRedirect.new(status, path, source_location) if String === path
|
|
211
214
|
|
|
212
215
|
block = path if path.respond_to? :call
|
|
213
216
|
raise ArgumentError, "redirection argument not supported" unless block
|
|
214
|
-
Redirect.new status, block
|
|
217
|
+
Redirect.new status, block, source_location
|
|
215
218
|
end
|
|
216
219
|
end
|
|
217
220
|
end
|
|
@@ -29,7 +29,7 @@ module ActionDispatch
|
|
|
29
29
|
def from_requirements(requirements)
|
|
30
30
|
routes.find { |route| route.requirements == requirements }
|
|
31
31
|
end
|
|
32
|
-
# :
|
|
32
|
+
# :enddoc:
|
|
33
33
|
|
|
34
34
|
# Since the router holds references to many parts of the system like engines,
|
|
35
35
|
# controllers and the application itself, inspecting the route set can actually
|
|
@@ -59,8 +59,6 @@ module ActionDispatch
|
|
|
59
59
|
private
|
|
60
60
|
def controller(req)
|
|
61
61
|
req.controller_class
|
|
62
|
-
rescue NameError => e
|
|
63
|
-
raise ActionController::RoutingError, e.message, e.backtrace
|
|
64
62
|
end
|
|
65
63
|
|
|
66
64
|
def dispatch(controller, action, req, res)
|
|
@@ -351,7 +349,7 @@ module ActionDispatch
|
|
|
351
349
|
PATH = ->(options) { ActionDispatch::Http::URL.path_for(options) }
|
|
352
350
|
UNKNOWN = ->(options) { ActionDispatch::Http::URL.url_for(options) }
|
|
353
351
|
|
|
354
|
-
attr_accessor :formatter, :set, :named_routes, :
|
|
352
|
+
attr_accessor :formatter, :set, :named_routes, :router
|
|
355
353
|
attr_accessor :disable_clear_and_finalize, :resources_path_names
|
|
356
354
|
attr_accessor :default_url_options, :draw_paths
|
|
357
355
|
attr_reader :env_key, :polymorphic_mappings
|
|
@@ -363,7 +361,7 @@ module ActionDispatch
|
|
|
363
361
|
end
|
|
364
362
|
|
|
365
363
|
def self.new_with_config(config)
|
|
366
|
-
route_set_config = DEFAULT_CONFIG
|
|
364
|
+
route_set_config = DEFAULT_CONFIG.dup
|
|
367
365
|
|
|
368
366
|
# engines apparently don't have this set
|
|
369
367
|
if config.respond_to? :relative_url_root
|
|
@@ -374,14 +372,18 @@ module ActionDispatch
|
|
|
374
372
|
route_set_config.api_only = config.api_only
|
|
375
373
|
end
|
|
376
374
|
|
|
375
|
+
if config.respond_to? :default_scope
|
|
376
|
+
route_set_config.default_scope = config.default_scope
|
|
377
|
+
end
|
|
378
|
+
|
|
377
379
|
new route_set_config
|
|
378
380
|
end
|
|
379
381
|
|
|
380
|
-
Config = Struct.new :relative_url_root, :api_only
|
|
382
|
+
Config = Struct.new :relative_url_root, :api_only, :default_scope
|
|
381
383
|
|
|
382
|
-
DEFAULT_CONFIG = Config.new(nil, false)
|
|
384
|
+
DEFAULT_CONFIG = Config.new(nil, false, nil)
|
|
383
385
|
|
|
384
|
-
def initialize(config = DEFAULT_CONFIG)
|
|
386
|
+
def initialize(config = DEFAULT_CONFIG.dup)
|
|
385
387
|
self.named_routes = NamedRouteCollection.new
|
|
386
388
|
self.resources_path_names = self.class.default_resources_path_names
|
|
387
389
|
self.default_url_options = {}
|
|
@@ -416,6 +418,14 @@ module ActionDispatch
|
|
|
416
418
|
@config.api_only
|
|
417
419
|
end
|
|
418
420
|
|
|
421
|
+
def default_scope
|
|
422
|
+
@config.default_scope
|
|
423
|
+
end
|
|
424
|
+
|
|
425
|
+
def default_scope=(new_default_scope)
|
|
426
|
+
@config.default_scope = new_default_scope
|
|
427
|
+
end
|
|
428
|
+
|
|
419
429
|
def request_class
|
|
420
430
|
ActionDispatch::Request
|
|
421
431
|
end
|
|
@@ -647,14 +657,14 @@ module ActionDispatch
|
|
|
647
657
|
if route.segment_keys.include?(:controller)
|
|
648
658
|
ActionDispatch.deprecator.warn(<<-MSG.squish)
|
|
649
659
|
Using a dynamic :controller segment in a route is deprecated and
|
|
650
|
-
will be removed in Rails
|
|
660
|
+
will be removed in Rails 9.0.
|
|
651
661
|
MSG
|
|
652
662
|
end
|
|
653
663
|
|
|
654
664
|
if route.segment_keys.include?(:action)
|
|
655
665
|
ActionDispatch.deprecator.warn(<<-MSG.squish)
|
|
656
666
|
Using a dynamic :action segment in a route is deprecated and
|
|
657
|
-
will be removed in Rails
|
|
667
|
+
will be removed in Rails 9.0.
|
|
658
668
|
MSG
|
|
659
669
|
end
|
|
660
670
|
|
|
@@ -917,7 +927,7 @@ module ActionDispatch
|
|
|
917
927
|
params.each do |key, value|
|
|
918
928
|
if value.is_a?(String)
|
|
919
929
|
value = value.dup.force_encoding(Encoding::BINARY)
|
|
920
|
-
params[key] = RFC2396_PARSER.unescape(value)
|
|
930
|
+
params[key] = URI::RFC2396_PARSER.unescape(value)
|
|
921
931
|
end
|
|
922
932
|
end
|
|
923
933
|
req.path_parameters = params
|
|
@@ -941,6 +951,5 @@ module ActionDispatch
|
|
|
941
951
|
end
|
|
942
952
|
end
|
|
943
953
|
end
|
|
944
|
-
# :startdoc:
|
|
945
954
|
end
|
|
946
955
|
end
|
|
@@ -54,6 +54,7 @@ module ActionDispatch
|
|
|
54
54
|
# dependent part.
|
|
55
55
|
def merge_script_names(previous_script_name, new_script_name)
|
|
56
56
|
return new_script_name unless previous_script_name
|
|
57
|
+
new_script_name = new_script_name.chomp("/")
|
|
57
58
|
|
|
58
59
|
resolved_parts = new_script_name.count("/")
|
|
59
60
|
previous_parts = previous_script_name.count("/")
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActionDispatch
|
|
4
|
+
class StructuredEventSubscriber < ActiveSupport::StructuredEventSubscriber # :nodoc:
|
|
5
|
+
def redirect(event)
|
|
6
|
+
payload = event.payload
|
|
7
|
+
status = payload[:status]
|
|
8
|
+
|
|
9
|
+
emit_event("action_dispatch.redirect", {
|
|
10
|
+
location: payload[:location],
|
|
11
|
+
status: status,
|
|
12
|
+
status_name: Rack::Utils::HTTP_STATUS_CODES[status],
|
|
13
|
+
duration_ms: event.duration.round(2),
|
|
14
|
+
source_location: payload[:source_location]
|
|
15
|
+
})
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
ActionDispatch::StructuredEventSubscriber.attach_to :action_dispatch
|
|
@@ -22,8 +22,8 @@ module ActionDispatch
|
|
|
22
22
|
#
|
|
23
23
|
# To create a system test in your application, extend your test class from
|
|
24
24
|
# `ApplicationSystemTestCase`. System tests use Capybara as a base and allow you
|
|
25
|
-
# to configure the settings through
|
|
26
|
-
#
|
|
25
|
+
# to configure the settings through the `application_system_test_case.rb` file,
|
|
26
|
+
# which is created when you generate your first system test.
|
|
27
27
|
#
|
|
28
28
|
# Here is an example system test:
|
|
29
29
|
#
|
|
@@ -41,7 +41,7 @@ module ActionDispatch
|
|
|
41
41
|
# end
|
|
42
42
|
# end
|
|
43
43
|
#
|
|
44
|
-
# When generating
|
|
44
|
+
# When generating system tests, an
|
|
45
45
|
# `application_system_test_case.rb` file will also be generated containing the
|
|
46
46
|
# base class for system testing. This is where you can change the driver, add
|
|
47
47
|
# Capybara settings, and other configuration for your system tests.
|
|
@@ -9,7 +9,6 @@ module ActionDispatch
|
|
|
9
9
|
|
|
10
10
|
def initialize(name)
|
|
11
11
|
@name = name
|
|
12
|
-
set_default_options
|
|
13
12
|
end
|
|
14
13
|
|
|
15
14
|
def type
|
|
@@ -27,9 +26,9 @@ module ActionDispatch
|
|
|
27
26
|
@options ||=
|
|
28
27
|
case type
|
|
29
28
|
when :chrome
|
|
30
|
-
|
|
29
|
+
default_chrome_options
|
|
31
30
|
when :firefox
|
|
32
|
-
|
|
31
|
+
default_firefox_options
|
|
33
32
|
end
|
|
34
33
|
end
|
|
35
34
|
|
|
@@ -49,26 +48,18 @@ module ActionDispatch
|
|
|
49
48
|
end
|
|
50
49
|
|
|
51
50
|
private
|
|
52
|
-
def
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
end
|
|
51
|
+
def default_chrome_options
|
|
52
|
+
options = ::Selenium::WebDriver::Chrome::Options.new
|
|
53
|
+
options.add_argument("--disable-search-engine-choice-screen")
|
|
54
|
+
options.add_argument("--headless") if name == :headless_chrome
|
|
55
|
+
options.add_argument("--disable-gpu") if Gem.win_platform?
|
|
56
|
+
options
|
|
59
57
|
end
|
|
60
58
|
|
|
61
|
-
def
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def set_headless_firefox_browser_options
|
|
69
|
-
configure do |capabilities|
|
|
70
|
-
capabilities.add_argument("-headless")
|
|
71
|
-
end
|
|
59
|
+
def default_firefox_options
|
|
60
|
+
options = ::Selenium::WebDriver::Firefox::Options.new
|
|
61
|
+
options.add_argument("-headless") if name == :headless_firefox
|
|
62
|
+
options
|
|
72
63
|
end
|
|
73
64
|
|
|
74
65
|
def resolve_driver_path(namespace)
|
|
@@ -132,8 +132,8 @@ module ActionDispatch
|
|
|
132
132
|
end
|
|
133
133
|
|
|
134
134
|
def display_image(html:, screenshot_output:)
|
|
135
|
-
message = +"[Screenshot Image]: #{image_path}\n"
|
|
136
|
-
message << +"[Screenshot HTML]: #{html_path}\n" if html
|
|
135
|
+
message = +"[Screenshot Image]: #{image_path} \n"
|
|
136
|
+
message << +"[Screenshot HTML]: #{html_path} \n" if html
|
|
137
137
|
|
|
138
138
|
case screenshot_output || output_type
|
|
139
139
|
when "artifact"
|
|
@@ -71,6 +71,20 @@ module ActionDispatch
|
|
|
71
71
|
assert_operator redirect_expected, :===, redirect_is, message
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
+
# Asserts that the given +text+ is present somewhere in the response body.
|
|
75
|
+
#
|
|
76
|
+
# assert_in_body fixture(:name).description
|
|
77
|
+
def assert_in_body(text)
|
|
78
|
+
assert_match(/#{Regexp.escape(text)}/, @response.body)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Asserts that the given +text+ is not present anywhere in the response body.
|
|
82
|
+
#
|
|
83
|
+
# assert_not_in_body fixture(:name).description
|
|
84
|
+
def assert_not_in_body(text)
|
|
85
|
+
assert_no_match(/#{Regexp.escape(text)}/, @response.body)
|
|
86
|
+
end
|
|
87
|
+
|
|
74
88
|
private
|
|
75
89
|
# Proxy to to_param if the object will respond to it.
|
|
76
90
|
def parameterize(value)
|
|
@@ -87,8 +101,13 @@ module ActionDispatch
|
|
|
87
101
|
end
|
|
88
102
|
|
|
89
103
|
def generate_response_message(expected, actual = @response.response_code)
|
|
90
|
-
|
|
91
|
-
|
|
104
|
+
lambda do
|
|
105
|
+
(+"Expected response to be a <#{code_with_name(expected)}>,"\
|
|
106
|
+
" but was a <#{code_with_name(actual)}>").
|
|
107
|
+
concat(location_if_redirected).
|
|
108
|
+
concat(exception_if_present).
|
|
109
|
+
concat(response_body_if_short)
|
|
110
|
+
end
|
|
92
111
|
end
|
|
93
112
|
|
|
94
113
|
def response_body_if_short
|
|
@@ -96,6 +115,11 @@ module ActionDispatch
|
|
|
96
115
|
"\nResponse body: #{@response.body}"
|
|
97
116
|
end
|
|
98
117
|
|
|
118
|
+
def exception_if_present
|
|
119
|
+
return "" unless ex = @request&.env&.[]("action_dispatch.exception")
|
|
120
|
+
"\n\nException while processing request: #{Minitest::UnexpectedError.new(ex).message}\n"
|
|
121
|
+
end
|
|
122
|
+
|
|
99
123
|
def location_if_redirected
|
|
100
124
|
return "" unless @response.redirection? && @response.location.present?
|
|
101
125
|
location = normalize_argument_to_redirection(@response.location)
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
require "uri"
|
|
6
6
|
require "active_support/core_ext/hash/indifferent_access"
|
|
7
7
|
require "active_support/core_ext/string/access"
|
|
8
|
+
require "active_support/core_ext/module/redefine_method"
|
|
8
9
|
require "action_controller/metal/exceptions"
|
|
9
10
|
|
|
10
11
|
module ActionDispatch
|
|
@@ -20,38 +21,51 @@ module ActionDispatch
|
|
|
20
21
|
module ClassMethods
|
|
21
22
|
def with_routing(&block)
|
|
22
23
|
old_routes = nil
|
|
24
|
+
old_routes_call_method = nil
|
|
23
25
|
old_integration_session = nil
|
|
24
26
|
|
|
25
27
|
setup do
|
|
26
|
-
old_routes = app.routes
|
|
28
|
+
old_routes = initialize_lazy_routes(app.routes)
|
|
29
|
+
old_routes_call_method = old_routes.method(:call)
|
|
27
30
|
old_integration_session = integration_session
|
|
28
31
|
create_routes(&block)
|
|
29
32
|
end
|
|
30
33
|
|
|
31
34
|
teardown do
|
|
32
|
-
reset_routes(old_routes, old_integration_session)
|
|
35
|
+
reset_routes(old_routes, old_routes_call_method, old_integration_session)
|
|
33
36
|
end
|
|
34
37
|
end
|
|
35
38
|
end
|
|
36
39
|
|
|
37
40
|
def with_routing(&block)
|
|
38
|
-
old_routes = app.routes
|
|
41
|
+
old_routes = initialize_lazy_routes(app.routes)
|
|
42
|
+
old_routes_call_method = old_routes.method(:call)
|
|
39
43
|
old_integration_session = integration_session
|
|
40
44
|
create_routes(&block)
|
|
41
45
|
ensure
|
|
42
|
-
reset_routes(old_routes, old_integration_session)
|
|
46
|
+
reset_routes(old_routes, old_routes_call_method, old_integration_session)
|
|
43
47
|
end
|
|
44
48
|
|
|
45
49
|
private
|
|
50
|
+
def initialize_lazy_routes(routes)
|
|
51
|
+
if defined?(Rails::Engine::LazyRouteSet) && routes.is_a?(Rails::Engine::LazyRouteSet)
|
|
52
|
+
routes.tap(&:routes)
|
|
53
|
+
else
|
|
54
|
+
routes
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
46
58
|
def create_routes
|
|
47
59
|
app = self.app
|
|
48
60
|
routes = ActionDispatch::Routing::RouteSet.new
|
|
49
|
-
|
|
61
|
+
|
|
62
|
+
@original_routes ||= app.routes
|
|
63
|
+
@original_routes.singleton_class.redefine_method(:call, &routes.method(:call))
|
|
64
|
+
|
|
50
65
|
https = integration_session.https?
|
|
51
66
|
host = integration_session.host
|
|
52
67
|
|
|
53
68
|
app.instance_variable_set(:@routes, routes)
|
|
54
|
-
app.instance_variable_set(:@app, rack_app)
|
|
55
69
|
@integration_session = Class.new(ActionDispatch::Integration::Session) do
|
|
56
70
|
include app.routes.url_helpers
|
|
57
71
|
include app.routes.mounted_helpers
|
|
@@ -63,11 +77,9 @@ module ActionDispatch
|
|
|
63
77
|
yield routes
|
|
64
78
|
end
|
|
65
79
|
|
|
66
|
-
def reset_routes(old_routes, old_integration_session)
|
|
67
|
-
old_rack_app = app.config.middleware.build(old_routes)
|
|
68
|
-
|
|
80
|
+
def reset_routes(old_routes, old_routes_call_method, old_integration_session)
|
|
69
81
|
app.instance_variable_set(:@routes, old_routes)
|
|
70
|
-
|
|
82
|
+
@original_routes.singleton_class.redefine_method(:call, &old_routes_call_method)
|
|
71
83
|
@integration_session = old_integration_session
|
|
72
84
|
@routes = old_routes
|
|
73
85
|
end
|
|
@@ -118,9 +130,9 @@ module ActionDispatch
|
|
|
118
130
|
# assert_equal "/users", users_path
|
|
119
131
|
# end
|
|
120
132
|
#
|
|
121
|
-
def with_routing(&block)
|
|
133
|
+
def with_routing(config = nil, &block)
|
|
122
134
|
old_routes, old_controller = @routes, @controller
|
|
123
|
-
create_routes(&block)
|
|
135
|
+
create_routes(config, &block)
|
|
124
136
|
ensure
|
|
125
137
|
reset_routes(old_routes, old_controller)
|
|
126
138
|
end
|
|
@@ -267,8 +279,8 @@ module ActionDispatch
|
|
|
267
279
|
end
|
|
268
280
|
|
|
269
281
|
private
|
|
270
|
-
def create_routes
|
|
271
|
-
@routes = ActionDispatch::Routing::RouteSet.new
|
|
282
|
+
def create_routes(config = nil)
|
|
283
|
+
@routes = ActionDispatch::Routing::RouteSet.new(config || ActionDispatch::Routing::RouteSet::DEFAULT_CONFIG)
|
|
272
284
|
if @controller
|
|
273
285
|
@controller = @controller.clone
|
|
274
286
|
_routes = @routes
|
|
@@ -336,7 +348,7 @@ module ActionDispatch
|
|
|
336
348
|
def fail_on(exception_class, message)
|
|
337
349
|
yield
|
|
338
350
|
rescue exception_class => e
|
|
339
|
-
|
|
351
|
+
flunk(message || e.message)
|
|
340
352
|
end
|
|
341
353
|
end
|
|
342
354
|
end
|
|
@@ -184,7 +184,7 @@ module ActionDispatch
|
|
|
184
184
|
# Returns `true` if the session is mimicking a secure HTTPS request.
|
|
185
185
|
#
|
|
186
186
|
# if session.https?
|
|
187
|
-
# ...
|
|
187
|
+
# # ...
|
|
188
188
|
# end
|
|
189
189
|
def https?
|
|
190
190
|
@https
|
|
@@ -203,7 +203,7 @@ module ActionDispatch
|
|
|
203
203
|
# * `env`: Additional env to pass, as a Hash. The headers will be merged into
|
|
204
204
|
# the Rack env hash.
|
|
205
205
|
# * `xhr`: Set to `true` if you want to make an Ajax request. Adds request
|
|
206
|
-
# headers characteristic of XMLHttpRequest e.g. HTTP_X_REQUESTED_WITH
|
|
206
|
+
# headers characteristic of `XMLHttpRequest`, e.g. `HTTP_X_REQUESTED_WITH`. The
|
|
207
207
|
# headers will be merged into the Rack env hash.
|
|
208
208
|
# * `as`: Used for encoding the request with different content type. Supports
|
|
209
209
|
# `:json` by default and will set the appropriate request headers. The
|
|
@@ -218,9 +218,10 @@ module ActionDispatch
|
|
|
218
218
|
# This method returns the response status, after performing the request.
|
|
219
219
|
# Furthermore, if this method was called from an ActionDispatch::IntegrationTest
|
|
220
220
|
# object, then that object's `@response` instance variable will point to a
|
|
221
|
-
#
|
|
221
|
+
# ActionDispatch::TestResponse object which one can use to inspect the details of the response.
|
|
222
222
|
#
|
|
223
223
|
# Example:
|
|
224
|
+
#
|
|
224
225
|
# process :get, '/author', params: { since: 201501011400 }
|
|
225
226
|
def process(method, path, params: nil, headers: nil, env: nil, xhr: false, as: nil)
|
|
226
227
|
request_encoder = RequestEncoder.encoder(as)
|
|
@@ -284,7 +285,17 @@ module ActionDispatch
|
|
|
284
285
|
|
|
285
286
|
# NOTE: rack-test v0.5 doesn't build a default uri correctly Make sure requested
|
|
286
287
|
# path is always a full URI.
|
|
287
|
-
|
|
288
|
+
uri = build_full_uri(path, request_env)
|
|
289
|
+
|
|
290
|
+
if method == :get && String === request_env[:params]
|
|
291
|
+
# rack-test will needlessly parse and rebuild a :params
|
|
292
|
+
# querystring, using Rack's query parser. At best that's a
|
|
293
|
+
# waste of time; at worst it can change the value.
|
|
294
|
+
|
|
295
|
+
uri << "?" << request_env.delete(:params)
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
session.request(uri, request_env)
|
|
288
299
|
|
|
289
300
|
@request_count += 1
|
|
290
301
|
@request = ActionDispatch::Request.new(session.last_request.env)
|
|
@@ -539,7 +550,7 @@ module ActionDispatch
|
|
|
539
550
|
# https!(false)
|
|
540
551
|
# get "/articles/all"
|
|
541
552
|
# assert_response :success
|
|
542
|
-
#
|
|
553
|
+
# assert_dom 'h1', 'Articles'
|
|
543
554
|
# end
|
|
544
555
|
# end
|
|
545
556
|
#
|
|
@@ -578,7 +589,7 @@ module ActionDispatch
|
|
|
578
589
|
# def browses_site
|
|
579
590
|
# get "/products/all"
|
|
580
591
|
# assert_response :success
|
|
581
|
-
#
|
|
592
|
+
# assert_dom 'h1', 'Products'
|
|
582
593
|
# end
|
|
583
594
|
# end
|
|
584
595
|
#
|
|
@@ -611,7 +622,7 @@ module ActionDispatch
|
|
|
611
622
|
# end
|
|
612
623
|
#
|
|
613
624
|
# assert_response :success
|
|
614
|
-
# assert_equal({ id
|
|
625
|
+
# assert_equal({ "id" => Article.last.id, "title" => "Ahoy!" }, response.parsed_body)
|
|
615
626
|
# end
|
|
616
627
|
# end
|
|
617
628
|
#
|
data/lib/action_dispatch.rb
CHANGED
|
@@ -30,7 +30,6 @@ require "active_support/core_ext/module/attribute_accessors"
|
|
|
30
30
|
|
|
31
31
|
require "action_pack"
|
|
32
32
|
require "rack"
|
|
33
|
-
require "uri"
|
|
34
33
|
require "action_dispatch/deprecator"
|
|
35
34
|
|
|
36
35
|
module Rack # :nodoc:
|
|
@@ -48,16 +47,19 @@ end
|
|
|
48
47
|
module ActionDispatch
|
|
49
48
|
extend ActiveSupport::Autoload
|
|
50
49
|
|
|
51
|
-
RFC2396_PARSER = defined?(URI::RFC2396_PARSER) ? URI::RFC2396_PARSER : URI::RFC2396_Parser.new
|
|
52
|
-
private_constant :RFC2396_PARSER
|
|
53
|
-
|
|
54
50
|
class MissingController < NameError
|
|
55
51
|
end
|
|
56
52
|
|
|
57
53
|
eager_autoload do
|
|
58
54
|
autoload_under "http" do
|
|
59
55
|
autoload :ContentSecurityPolicy
|
|
56
|
+
autoload :InvalidParameterError, "action_dispatch/http/param_error"
|
|
57
|
+
autoload :ParamBuilder
|
|
58
|
+
autoload :ParamError
|
|
59
|
+
autoload :ParameterTypeError, "action_dispatch/http/param_error"
|
|
60
|
+
autoload :ParamsTooDeepError, "action_dispatch/http/param_error"
|
|
60
61
|
autoload :PermissionsPolicy
|
|
62
|
+
autoload :QueryParser
|
|
61
63
|
autoload :Request
|
|
62
64
|
autoload :Response
|
|
63
65
|
end
|
|
@@ -136,6 +138,14 @@ module ActionDispatch
|
|
|
136
138
|
|
|
137
139
|
autoload :SystemTestCase, "action_dispatch/system_test_case"
|
|
138
140
|
|
|
141
|
+
##
|
|
142
|
+
# :singleton-method:
|
|
143
|
+
#
|
|
144
|
+
# Specifies if the methods calling redirects in controllers and routes should
|
|
145
|
+
# be logged below their relevant log lines. Defaults to false.
|
|
146
|
+
singleton_class.attr_accessor :verbose_redirect_logs
|
|
147
|
+
self.verbose_redirect_logs = false
|
|
148
|
+
|
|
139
149
|
def eager_load!
|
|
140
150
|
super
|
|
141
151
|
Routing.eager_load!
|