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.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +394 -119
  3. data/lib/abstract_controller/asset_paths.rb +4 -2
  4. data/lib/abstract_controller/base.rb +11 -5
  5. data/lib/abstract_controller/caching.rb +6 -3
  6. data/lib/abstract_controller/callbacks.rb +6 -0
  7. data/lib/abstract_controller/logger.rb +2 -1
  8. data/lib/abstract_controller/rendering.rb +0 -1
  9. data/lib/action_controller/api.rb +1 -0
  10. data/lib/action_controller/base.rb +3 -2
  11. data/lib/action_controller/caching.rb +1 -2
  12. data/lib/action_controller/form_builder.rb +4 -4
  13. data/lib/action_controller/log_subscriber.rb +22 -3
  14. data/lib/action_controller/metal/allow_browser.rb +12 -2
  15. data/lib/action_controller/metal/conditional_get.rb +30 -1
  16. data/lib/action_controller/metal/data_streaming.rb +5 -5
  17. data/lib/action_controller/metal/exceptions.rb +5 -0
  18. data/lib/action_controller/metal/flash.rb +1 -4
  19. data/lib/action_controller/metal/head.rb +3 -1
  20. data/lib/action_controller/metal/instrumentation.rb +1 -2
  21. data/lib/action_controller/metal/live.rb +65 -25
  22. data/lib/action_controller/metal/permissions_policy.rb +9 -0
  23. data/lib/action_controller/metal/rate_limiting.rb +39 -9
  24. data/lib/action_controller/metal/redirecting.rb +105 -13
  25. data/lib/action_controller/metal/renderers.rb +29 -9
  26. data/lib/action_controller/metal/rendering.rb +7 -1
  27. data/lib/action_controller/metal/request_forgery_protection.rb +18 -10
  28. data/lib/action_controller/metal/rescue.rb +9 -0
  29. data/lib/action_controller/metal/streaming.rb +5 -84
  30. data/lib/action_controller/metal/strong_parameters.rb +277 -89
  31. data/lib/action_controller/railtie.rb +33 -15
  32. data/lib/action_controller/structured_event_subscriber.rb +116 -0
  33. data/lib/action_controller/test_case.rb +12 -2
  34. data/lib/action_dispatch/http/cache.rb +138 -11
  35. data/lib/action_dispatch/http/content_security_policy.rb +14 -1
  36. data/lib/action_dispatch/http/filter_parameters.rb +5 -3
  37. data/lib/action_dispatch/http/mime_negotiation.rb +55 -1
  38. data/lib/action_dispatch/http/mime_types.rb +1 -0
  39. data/lib/action_dispatch/http/param_builder.rb +187 -0
  40. data/lib/action_dispatch/http/param_error.rb +26 -0
  41. data/lib/action_dispatch/http/parameters.rb +3 -3
  42. data/lib/action_dispatch/http/permissions_policy.rb +6 -0
  43. data/lib/action_dispatch/http/query_parser.rb +55 -0
  44. data/lib/action_dispatch/http/request.rb +70 -21
  45. data/lib/action_dispatch/http/response.rb +50 -16
  46. data/lib/action_dispatch/http/url.rb +110 -14
  47. data/lib/action_dispatch/journey/gtg/simulator.rb +33 -12
  48. data/lib/action_dispatch/journey/gtg/transition_table.rb +33 -41
  49. data/lib/action_dispatch/journey/nodes/node.rb +2 -1
  50. data/lib/action_dispatch/journey/parser.rb +99 -196
  51. data/lib/action_dispatch/journey/route.rb +45 -31
  52. data/lib/action_dispatch/journey/router/utils.rb +8 -14
  53. data/lib/action_dispatch/journey/router.rb +59 -81
  54. data/lib/action_dispatch/journey/routes.rb +7 -0
  55. data/lib/action_dispatch/journey/scanner.rb +44 -42
  56. data/lib/action_dispatch/journey/visitors.rb +55 -23
  57. data/lib/action_dispatch/journey/visualizer/fsm.js +4 -6
  58. data/lib/action_dispatch/log_subscriber.rb +7 -3
  59. data/lib/action_dispatch/middleware/cookies.rb +8 -4
  60. data/lib/action_dispatch/middleware/debug_exceptions.rb +24 -5
  61. data/lib/action_dispatch/middleware/debug_view.rb +11 -5
  62. data/lib/action_dispatch/middleware/exception_wrapper.rb +11 -11
  63. data/lib/action_dispatch/middleware/executor.rb +12 -2
  64. data/lib/action_dispatch/middleware/public_exceptions.rb +1 -5
  65. data/lib/action_dispatch/middleware/remote_ip.rb +11 -5
  66. data/lib/action_dispatch/middleware/request_id.rb +2 -1
  67. data/lib/action_dispatch/middleware/session/cache_store.rb +17 -0
  68. data/lib/action_dispatch/middleware/ssl.rb +13 -3
  69. data/lib/action_dispatch/middleware/templates/rescues/_copy_button.html.erb +1 -0
  70. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +3 -5
  71. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +9 -5
  72. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +1 -0
  73. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +1 -0
  74. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -0
  75. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -0
  76. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +50 -0
  77. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -0
  78. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -0
  79. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -0
  80. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -0
  81. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -0
  82. data/lib/action_dispatch/railtie.rb +21 -0
  83. data/lib/action_dispatch/request/session.rb +1 -0
  84. data/lib/action_dispatch/request/utils.rb +9 -3
  85. data/lib/action_dispatch/routing/inspector.rb +80 -57
  86. data/lib/action_dispatch/routing/mapper.rb +404 -223
  87. data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -2
  88. data/lib/action_dispatch/routing/redirection.rb +10 -7
  89. data/lib/action_dispatch/routing/route_set.rb +21 -12
  90. data/lib/action_dispatch/routing/routes_proxy.rb +1 -0
  91. data/lib/action_dispatch/structured_event_subscriber.rb +20 -0
  92. data/lib/action_dispatch/system_test_case.rb +3 -3
  93. data/lib/action_dispatch/system_testing/browser.rb +12 -21
  94. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +2 -2
  95. data/lib/action_dispatch/testing/assertions/response.rb +26 -2
  96. data/lib/action_dispatch/testing/assertions/routing.rb +27 -15
  97. data/lib/action_dispatch/testing/integration.rb +18 -7
  98. data/lib/action_dispatch.rb +14 -4
  99. data/lib/action_pack/gem_version.rb +2 -2
  100. metadata +18 -48
  101. data/lib/action_dispatch/journey/parser.y +0 -50
  102. 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
- # `form_for(@article)` without having to specify `:url` parameter for the
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
- # form_for([blog, @post]) # => "/blog/posts/1"
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 = args.extract_options!
206
- status = options.delete(:status) || 301
207
- path = args.shift
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
- # :stopdoc:
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, :default_scope, :router
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 7.2.
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 7.2.
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 your `application_system_test_case.rb` file
26
- # that is generated with a new application or scaffold.
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 an application or scaffold, an
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
- ::Selenium::WebDriver::Chrome::Options.new
29
+ default_chrome_options
31
30
  when :firefox
32
- ::Selenium::WebDriver::Firefox::Options.new
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 set_default_options
53
- case name
54
- when :headless_chrome
55
- set_headless_chrome_browser_options
56
- when :headless_firefox
57
- set_headless_firefox_browser_options
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 set_headless_chrome_browser_options
62
- configure do |capabilities|
63
- capabilities.add_argument("--headless")
64
- capabilities.add_argument("--disable-gpu") if Gem.win_platform?
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
- (+"Expected response to be a <#{code_with_name(expected)}>,"\
91
- " but was a <#{code_with_name(actual)}>").concat(location_if_redirected).concat(response_body_if_short)
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
- rack_app = app.config.middleware.build(routes)
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
- app.instance_variable_set(:@app, old_rack_app)
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
- raise Minitest::Assertion, message || e.message
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. The
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
- # Response object which one can use to inspect the details of the response.
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
- session.request(build_full_uri(path, request_env), request_env)
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
- # assert_select 'h1', 'Articles'
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
- # assert_select 'h1', 'Products'
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: Article.last.id, title: "Ahoy!" }, response.parsed_body)
625
+ # assert_equal({ "id" => Article.last.id, "title" => "Ahoy!" }, response.parsed_body)
615
626
  # end
616
627
  # end
617
628
  #
@@ -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!
@@ -9,8 +9,8 @@ module ActionPack
9
9
  end
10
10
 
11
11
  module VERSION
12
- MAJOR = 7
13
- MINOR = 2
12
+ MAJOR = 8
13
+ MINOR = 1
14
14
  TINY = 3
15
15
  PRE = nil
16
16