actionpack 7.2.1.1 → 8.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +108 -100
- data/lib/abstract_controller/helpers.rb +2 -0
- data/lib/abstract_controller/rendering.rb +0 -1
- data/lib/action_controller/api.rb +1 -0
- data/lib/action_controller/form_builder.rb +3 -3
- data/lib/action_controller/metal/allow_browser.rb +12 -2
- data/lib/action_controller/metal/conditional_get.rb +6 -3
- data/lib/action_controller/metal/http_authentication.rb +6 -3
- data/lib/action_controller/metal/instrumentation.rb +1 -2
- data/lib/action_controller/metal/live.rb +19 -8
- data/lib/action_controller/metal/rate_limiting.rb +13 -4
- data/lib/action_controller/metal/renderers.rb +2 -3
- data/lib/action_controller/metal/streaming.rb +5 -84
- data/lib/action_controller/metal/strong_parameters.rb +274 -88
- data/lib/action_controller/railtie.rb +1 -7
- data/lib/action_controller/test_case.rb +6 -5
- data/lib/action_dispatch/http/cache.rb +27 -10
- data/lib/action_dispatch/http/content_security_policy.rb +5 -8
- data/lib/action_dispatch/http/filter_parameters.rb +4 -9
- data/lib/action_dispatch/http/filter_redirect.rb +2 -9
- data/lib/action_dispatch/http/param_builder.rb +163 -0
- data/lib/action_dispatch/http/param_error.rb +26 -0
- data/lib/action_dispatch/http/permissions_policy.rb +2 -0
- data/lib/action_dispatch/http/query_parser.rb +31 -0
- data/lib/action_dispatch/http/request.rb +60 -16
- data/lib/action_dispatch/journey/parser.rb +99 -196
- data/lib/action_dispatch/journey/scanner.rb +40 -42
- data/lib/action_dispatch/middleware/cookies.rb +4 -2
- data/lib/action_dispatch/middleware/debug_exceptions.rb +16 -3
- data/lib/action_dispatch/middleware/debug_view.rb +0 -5
- data/lib/action_dispatch/middleware/exception_wrapper.rb +0 -6
- data/lib/action_dispatch/middleware/remote_ip.rb +5 -6
- data/lib/action_dispatch/middleware/request_id.rb +2 -1
- data/lib/action_dispatch/middleware/ssl.rb +14 -4
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +0 -3
- data/lib/action_dispatch/railtie.rb +2 -0
- data/lib/action_dispatch/request/utils.rb +9 -3
- data/lib/action_dispatch/routing/inspector.rb +1 -1
- data/lib/action_dispatch/routing/mapper.rb +91 -62
- data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -2
- data/lib/action_dispatch/routing/route_set.rb +20 -8
- data/lib/action_dispatch/system_testing/browser.rb +12 -21
- data/lib/action_dispatch/testing/assertions/response.rb +12 -2
- data/lib/action_dispatch/testing/assertions/routing.rb +4 -4
- data/lib/action_dispatch/testing/integration.rb +11 -1
- data/lib/action_dispatch.rb +6 -0
- data/lib/action_pack/gem_version.rb +4 -4
- metadata +15 -34
- data/lib/action_dispatch/journey/parser.y +0 -50
- data/lib/action_dispatch/journey/parser_extras.rb +0 -33
@@ -375,35 +375,18 @@ module ActionDispatch
|
|
375
375
|
Routing::RouteSet::Dispatcher.new raise_on_name_error
|
376
376
|
end
|
377
377
|
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
next if location.path.start_with?(action_dispatch_dir)
|
378
|
+
def route_source_location
|
379
|
+
if Mapper.route_source_locations
|
380
|
+
action_dispatch_dir = File.expand_path("..", __dir__)
|
381
|
+
Thread.each_caller_location do |location|
|
382
|
+
next if location.path.start_with?(action_dispatch_dir)
|
384
383
|
|
385
|
-
|
386
|
-
|
384
|
+
cleaned_path = Mapper.backtrace_cleaner.clean_frame(location.path)
|
385
|
+
next if cleaned_path.nil?
|
387
386
|
|
388
|
-
|
389
|
-
end
|
390
|
-
nil
|
391
|
-
end
|
392
|
-
end
|
393
|
-
else
|
394
|
-
def route_source_location
|
395
|
-
if Mapper.route_source_locations
|
396
|
-
action_dispatch_dir = File.expand_path("..", __dir__)
|
397
|
-
caller_locations.each do |location|
|
398
|
-
next if location.path.start_with?(action_dispatch_dir)
|
399
|
-
|
400
|
-
cleaned_path = Mapper.backtrace_cleaner.clean_frame(location.path)
|
401
|
-
next if cleaned_path.nil?
|
402
|
-
|
403
|
-
return "#{cleaned_path}:#{location.lineno}"
|
404
|
-
end
|
405
|
-
nil
|
387
|
+
return "#{cleaned_path}:#{location.lineno}"
|
406
388
|
end
|
389
|
+
nil
|
407
390
|
end
|
408
391
|
end
|
409
392
|
end
|
@@ -470,7 +453,6 @@ module ActionDispatch
|
|
470
453
|
# When a pattern points to an internal route, the route's `:action` and
|
471
454
|
# `:controller` should be set in options or hash shorthand. Examples:
|
472
455
|
#
|
473
|
-
# match 'photos/:id' => 'photos#show', via: :get
|
474
456
|
# match 'photos/:id', to: 'photos#show', via: :get
|
475
457
|
# match 'photos/:id', controller: 'photos', action: 'show', via: :get
|
476
458
|
#
|
@@ -614,10 +596,6 @@ module ActionDispatch
|
|
614
596
|
#
|
615
597
|
# mount SomeRackApp, at: "some_route"
|
616
598
|
#
|
617
|
-
# Alternatively:
|
618
|
-
#
|
619
|
-
# mount(SomeRackApp => "some_route")
|
620
|
-
#
|
621
599
|
# For options, see `match`, as `mount` uses it internally.
|
622
600
|
#
|
623
601
|
# All mounted applications come with routing helpers to access them. These are
|
@@ -625,7 +603,7 @@ module ActionDispatch
|
|
625
603
|
# `some_rack_app_path` or `some_rack_app_url`. To customize this helper's name,
|
626
604
|
# use the `:as` option:
|
627
605
|
#
|
628
|
-
# mount(SomeRackApp
|
606
|
+
# mount(SomeRackApp, at: "some_route", as: "exciting")
|
629
607
|
#
|
630
608
|
# This will generate the `exciting_path` and `exciting_url` helpers which can be
|
631
609
|
# used to navigate to this mounted app.
|
@@ -773,6 +751,16 @@ module ActionDispatch
|
|
773
751
|
map_method(:options, args, &block)
|
774
752
|
end
|
775
753
|
|
754
|
+
# Define a route that recognizes HTTP CONNECT (and GET) requests. More
|
755
|
+
# specifically this recognizes HTTP/1 protocol upgrade requests and HTTP/2
|
756
|
+
# CONNECT requests with the protocol pseudo header. For supported arguments,
|
757
|
+
# see [match](rdoc-ref:Base#match)
|
758
|
+
#
|
759
|
+
# connect 'live', to: 'live#index'
|
760
|
+
def connect(*args, &block)
|
761
|
+
map_method([:get, :connect], args, &block)
|
762
|
+
end
|
763
|
+
|
776
764
|
private
|
777
765
|
def map_method(method, args, &block)
|
778
766
|
options = args.extract_options!
|
@@ -1048,6 +1036,7 @@ module ActionDispatch
|
|
1048
1036
|
end
|
1049
1037
|
|
1050
1038
|
# Allows you to set default parameters for a route, such as this:
|
1039
|
+
#
|
1051
1040
|
# defaults id: 'home' do
|
1052
1041
|
# match 'scoped_pages/(:id)', to: 'pages#show'
|
1053
1042
|
# end
|
@@ -1173,6 +1162,16 @@ module ActionDispatch
|
|
1173
1162
|
CANONICAL_ACTIONS = %w(index create new show update destroy)
|
1174
1163
|
|
1175
1164
|
class Resource # :nodoc:
|
1165
|
+
class << self
|
1166
|
+
def default_actions(api_only)
|
1167
|
+
if api_only
|
1168
|
+
[:index, :create, :show, :update, :destroy]
|
1169
|
+
else
|
1170
|
+
[:index, :create, :new, :show, :update, :destroy, :edit]
|
1171
|
+
end
|
1172
|
+
end
|
1173
|
+
end
|
1174
|
+
|
1176
1175
|
attr_reader :controller, :path, :param
|
1177
1176
|
|
1178
1177
|
def initialize(entities, api_only, shallow, options = {})
|
@@ -1180,6 +1179,11 @@ module ActionDispatch
|
|
1180
1179
|
raise ArgumentError, ":param option can't contain colons"
|
1181
1180
|
end
|
1182
1181
|
|
1182
|
+
valid_actions = self.class.default_actions(false) # ignore api_only for this validation
|
1183
|
+
if invalid_actions = invalid_only_except_options(options, valid_actions).presence
|
1184
|
+
raise ArgumentError, ":only and :except must include only #{valid_actions}, but also included #{invalid_actions}"
|
1185
|
+
end
|
1186
|
+
|
1183
1187
|
@name = entities.to_s
|
1184
1188
|
@path = (options[:path] || @name).to_s
|
1185
1189
|
@controller = (options[:controller] || @name).to_s
|
@@ -1193,11 +1197,7 @@ module ActionDispatch
|
|
1193
1197
|
end
|
1194
1198
|
|
1195
1199
|
def default_actions
|
1196
|
-
|
1197
|
-
[:index, :create, :show, :update, :destroy]
|
1198
|
-
else
|
1199
|
-
[:index, :create, :new, :show, :update, :destroy, :edit]
|
1200
|
-
end
|
1200
|
+
self.class.default_actions(@api_only)
|
1201
1201
|
end
|
1202
1202
|
|
1203
1203
|
def actions
|
@@ -1265,9 +1265,24 @@ module ActionDispatch
|
|
1265
1265
|
end
|
1266
1266
|
|
1267
1267
|
def singleton?; false; end
|
1268
|
+
|
1269
|
+
private
|
1270
|
+
def invalid_only_except_options(options, valid_actions)
|
1271
|
+
options.values_at(:only, :except).flatten.compact.uniq.map(&:to_sym) - valid_actions
|
1272
|
+
end
|
1268
1273
|
end
|
1269
1274
|
|
1270
1275
|
class SingletonResource < Resource # :nodoc:
|
1276
|
+
class << self
|
1277
|
+
def default_actions(api_only)
|
1278
|
+
if api_only
|
1279
|
+
[:show, :create, :update, :destroy]
|
1280
|
+
else
|
1281
|
+
[:show, :create, :update, :destroy, :new, :edit]
|
1282
|
+
end
|
1283
|
+
end
|
1284
|
+
end
|
1285
|
+
|
1271
1286
|
def initialize(entities, api_only, shallow, options)
|
1272
1287
|
super
|
1273
1288
|
@as = nil
|
@@ -1276,11 +1291,7 @@ module ActionDispatch
|
|
1276
1291
|
end
|
1277
1292
|
|
1278
1293
|
def default_actions
|
1279
|
-
|
1280
|
-
[:show, :create, :update, :destroy]
|
1281
|
-
else
|
1282
|
-
[:show, :create, :update, :destroy, :new, :edit]
|
1283
|
-
end
|
1294
|
+
self.class.default_actions(@api_only)
|
1284
1295
|
end
|
1285
1296
|
|
1286
1297
|
def plural
|
@@ -1341,7 +1352,7 @@ module ActionDispatch
|
|
1341
1352
|
end
|
1342
1353
|
|
1343
1354
|
with_scope_level(:resource) do
|
1344
|
-
options = apply_action_options options
|
1355
|
+
options = apply_action_options :resource, options
|
1345
1356
|
resource_scope(SingletonResource.new(resources.pop, api_only?, @scope[:shallow], options)) do
|
1346
1357
|
yield if block_given?
|
1347
1358
|
|
@@ -1511,7 +1522,7 @@ module ActionDispatch
|
|
1511
1522
|
end
|
1512
1523
|
|
1513
1524
|
with_scope_level(:resources) do
|
1514
|
-
options = apply_action_options options
|
1525
|
+
options = apply_action_options :resources, options
|
1515
1526
|
resource_scope(Resource.new(resources.pop, api_only?, @scope[:shallow], options)) do
|
1516
1527
|
yield if block_given?
|
1517
1528
|
|
@@ -1672,7 +1683,6 @@ module ActionDispatch
|
|
1672
1683
|
# Matches a URL pattern to one or more routes. For more information, see
|
1673
1684
|
# [match](rdoc-ref:Base#match).
|
1674
1685
|
#
|
1675
|
-
# match 'path' => 'controller#action', via: :patch
|
1676
1686
|
# match 'path', to: 'controller#action', via: :post
|
1677
1687
|
# match 'path', 'otherpath', on: :member, via: :get
|
1678
1688
|
def match(path, *rest, &block)
|
@@ -1781,17 +1791,32 @@ module ActionDispatch
|
|
1781
1791
|
false
|
1782
1792
|
end
|
1783
1793
|
|
1784
|
-
def apply_action_options(options)
|
1794
|
+
def apply_action_options(method, options)
|
1785
1795
|
return options if action_options? options
|
1786
|
-
options.merge scope_action_options
|
1796
|
+
options.merge scope_action_options(method)
|
1787
1797
|
end
|
1788
1798
|
|
1789
1799
|
def action_options?(options)
|
1790
1800
|
options[:only] || options[:except]
|
1791
1801
|
end
|
1792
1802
|
|
1793
|
-
def scope_action_options
|
1794
|
-
@scope[:action_options]
|
1803
|
+
def scope_action_options(method)
|
1804
|
+
return {} unless @scope[:action_options]
|
1805
|
+
|
1806
|
+
actions = applicable_actions_for(method)
|
1807
|
+
@scope[:action_options].dup.tap do |options|
|
1808
|
+
(options[:only] = Array(options[:only]) & actions) if options[:only]
|
1809
|
+
(options[:except] = Array(options[:except]) & actions) if options[:except]
|
1810
|
+
end
|
1811
|
+
end
|
1812
|
+
|
1813
|
+
def applicable_actions_for(method)
|
1814
|
+
case method
|
1815
|
+
when :resource
|
1816
|
+
SingletonResource.default_actions(api_only?)
|
1817
|
+
when :resources
|
1818
|
+
Resource.default_actions(api_only?)
|
1819
|
+
end
|
1795
1820
|
end
|
1796
1821
|
|
1797
1822
|
def resource_scope?
|
@@ -1934,6 +1959,11 @@ module ActionDispatch
|
|
1934
1959
|
end
|
1935
1960
|
|
1936
1961
|
def map_match(paths, options)
|
1962
|
+
ActionDispatch.deprecator.warn(<<-MSG.squish) if paths.count > 1
|
1963
|
+
Mapping a route with multiple paths is deprecated and
|
1964
|
+
will be removed in Rails 8.1. Please use multiple method calls instead.
|
1965
|
+
MSG
|
1966
|
+
|
1937
1967
|
if (on = options[:on]) && !VALID_ON_OPTIONS.include?(on)
|
1938
1968
|
raise ArgumentError, "Unknown scope #{on.inspect} given to :on"
|
1939
1969
|
end
|
@@ -2024,7 +2054,7 @@ module ActionDispatch
|
|
2024
2054
|
name_for_action(options.delete(:as), action)
|
2025
2055
|
end
|
2026
2056
|
|
2027
|
-
path = Mapping.normalize_path URI::
|
2057
|
+
path = Mapping.normalize_path URI::RFC2396_PARSER.escape(path), formatted
|
2028
2058
|
ast = Journey::Parser.parse path
|
2029
2059
|
|
2030
2060
|
mapping = Mapping.build(@scope, @set, ast, controller, default_action, to, via, formatted, options_constraints, anchor, options)
|
@@ -2199,8 +2229,8 @@ module ActionDispatch
|
|
2199
2229
|
end
|
2200
2230
|
|
2201
2231
|
# Define custom polymorphic mappings of models to URLs. This alters the behavior
|
2202
|
-
# of `polymorphic_url` and consequently the behavior of `link_to
|
2203
|
-
# when passed a model instance, e.g:
|
2232
|
+
# of `polymorphic_url` and consequently the behavior of `link_to`, `form_with`
|
2233
|
+
# and `form_for` when passed a model instance, e.g:
|
2204
2234
|
#
|
2205
2235
|
# resource :basket
|
2206
2236
|
#
|
@@ -2209,7 +2239,7 @@ module ActionDispatch
|
|
2209
2239
|
# end
|
2210
2240
|
#
|
2211
2241
|
# This will now generate "/basket" when a `Basket` instance is passed to
|
2212
|
-
# `link_to` or `form_for` instead of the standard "/baskets/:id".
|
2242
|
+
# `link_to`, `form_with` or `form_for` instead of the standard "/baskets/:id".
|
2213
2243
|
#
|
2214
2244
|
# NOTE: This custom behavior only applies to simple polymorphic URLs where a
|
2215
2245
|
# single model instance is passed and not more complicated forms, e.g:
|
@@ -2266,9 +2296,9 @@ module ActionDispatch
|
|
2266
2296
|
|
2267
2297
|
attr_reader :parent, :scope_level
|
2268
2298
|
|
2269
|
-
def initialize(hash, parent =
|
2270
|
-
@hash = hash
|
2299
|
+
def initialize(hash, parent = ROOT, scope_level = nil)
|
2271
2300
|
@parent = parent
|
2301
|
+
@hash = parent ? parent.frame.merge(hash) : hash
|
2272
2302
|
@scope_level = scope_level
|
2273
2303
|
end
|
2274
2304
|
|
@@ -2281,7 +2311,7 @@ module ActionDispatch
|
|
2281
2311
|
end
|
2282
2312
|
|
2283
2313
|
def root?
|
2284
|
-
@parent
|
2314
|
+
@parent == ROOT
|
2285
2315
|
end
|
2286
2316
|
|
2287
2317
|
def resources?
|
@@ -2326,23 +2356,22 @@ module ActionDispatch
|
|
2326
2356
|
end
|
2327
2357
|
|
2328
2358
|
def [](key)
|
2329
|
-
|
2330
|
-
scope && scope.frame[key]
|
2359
|
+
frame[key]
|
2331
2360
|
end
|
2332
2361
|
|
2362
|
+
def frame; @hash; end
|
2363
|
+
|
2333
2364
|
include Enumerable
|
2334
2365
|
|
2335
2366
|
def each
|
2336
2367
|
node = self
|
2337
|
-
until node.equal?
|
2368
|
+
until node.equal? ROOT
|
2338
2369
|
yield node
|
2339
2370
|
node = node.parent
|
2340
2371
|
end
|
2341
2372
|
end
|
2342
2373
|
|
2343
|
-
|
2344
|
-
|
2345
|
-
NULL = Scope.new(nil, nil)
|
2374
|
+
ROOT = Scope.new({}, nil)
|
2346
2375
|
end
|
2347
2376
|
|
2348
2377
|
def initialize(set) # :nodoc:
|
@@ -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
|
@@ -351,7 +351,7 @@ module ActionDispatch
|
|
351
351
|
PATH = ->(options) { ActionDispatch::Http::URL.path_for(options) }
|
352
352
|
UNKNOWN = ->(options) { ActionDispatch::Http::URL.url_for(options) }
|
353
353
|
|
354
|
-
attr_accessor :formatter, :set, :named_routes, :
|
354
|
+
attr_accessor :formatter, :set, :named_routes, :router
|
355
355
|
attr_accessor :disable_clear_and_finalize, :resources_path_names
|
356
356
|
attr_accessor :default_url_options, :draw_paths
|
357
357
|
attr_reader :env_key, :polymorphic_mappings
|
@@ -363,7 +363,7 @@ module ActionDispatch
|
|
363
363
|
end
|
364
364
|
|
365
365
|
def self.new_with_config(config)
|
366
|
-
route_set_config = DEFAULT_CONFIG
|
366
|
+
route_set_config = DEFAULT_CONFIG.dup
|
367
367
|
|
368
368
|
# engines apparently don't have this set
|
369
369
|
if config.respond_to? :relative_url_root
|
@@ -374,14 +374,18 @@ module ActionDispatch
|
|
374
374
|
route_set_config.api_only = config.api_only
|
375
375
|
end
|
376
376
|
|
377
|
+
if config.respond_to? :default_scope
|
378
|
+
route_set_config.default_scope = config.default_scope
|
379
|
+
end
|
380
|
+
|
377
381
|
new route_set_config
|
378
382
|
end
|
379
383
|
|
380
|
-
Config = Struct.new :relative_url_root, :api_only
|
384
|
+
Config = Struct.new :relative_url_root, :api_only, :default_scope
|
381
385
|
|
382
|
-
DEFAULT_CONFIG = Config.new(nil, false)
|
386
|
+
DEFAULT_CONFIG = Config.new(nil, false, nil)
|
383
387
|
|
384
|
-
def initialize(config = DEFAULT_CONFIG)
|
388
|
+
def initialize(config = DEFAULT_CONFIG.dup)
|
385
389
|
self.named_routes = NamedRouteCollection.new
|
386
390
|
self.resources_path_names = self.class.default_resources_path_names
|
387
391
|
self.default_url_options = {}
|
@@ -416,6 +420,14 @@ module ActionDispatch
|
|
416
420
|
@config.api_only
|
417
421
|
end
|
418
422
|
|
423
|
+
def default_scope
|
424
|
+
@config.default_scope
|
425
|
+
end
|
426
|
+
|
427
|
+
def default_scope=(new_default_scope)
|
428
|
+
@config.default_scope = new_default_scope
|
429
|
+
end
|
430
|
+
|
419
431
|
def request_class
|
420
432
|
ActionDispatch::Request
|
421
433
|
end
|
@@ -647,14 +659,14 @@ module ActionDispatch
|
|
647
659
|
if route.segment_keys.include?(:controller)
|
648
660
|
ActionDispatch.deprecator.warn(<<-MSG.squish)
|
649
661
|
Using a dynamic :controller segment in a route is deprecated and
|
650
|
-
will be removed in Rails
|
662
|
+
will be removed in Rails 8.1.
|
651
663
|
MSG
|
652
664
|
end
|
653
665
|
|
654
666
|
if route.segment_keys.include?(:action)
|
655
667
|
ActionDispatch.deprecator.warn(<<-MSG.squish)
|
656
668
|
Using a dynamic :action segment in a route is deprecated and
|
657
|
-
will be removed in Rails
|
669
|
+
will be removed in Rails 8.1.
|
658
670
|
MSG
|
659
671
|
end
|
660
672
|
|
@@ -917,7 +929,7 @@ module ActionDispatch
|
|
917
929
|
params.each do |key, value|
|
918
930
|
if value.is_a?(String)
|
919
931
|
value = value.dup.force_encoding(Encoding::BINARY)
|
920
|
-
params[key] = URI::
|
932
|
+
params[key] = URI::RFC2396_PARSER.unescape(value)
|
921
933
|
end
|
922
934
|
end
|
923
935
|
req.path_parameters = params
|
@@ -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)
|
@@ -87,8 +87,13 @@ module ActionDispatch
|
|
87
87
|
end
|
88
88
|
|
89
89
|
def generate_response_message(expected, actual = @response.response_code)
|
90
|
-
|
91
|
-
|
90
|
+
lambda do
|
91
|
+
(+"Expected response to be a <#{code_with_name(expected)}>,"\
|
92
|
+
" but was a <#{code_with_name(actual)}>").
|
93
|
+
concat(location_if_redirected).
|
94
|
+
concat(exception_if_present).
|
95
|
+
concat(response_body_if_short)
|
96
|
+
end
|
92
97
|
end
|
93
98
|
|
94
99
|
def response_body_if_short
|
@@ -96,6 +101,11 @@ module ActionDispatch
|
|
96
101
|
"\nResponse body: #{@response.body}"
|
97
102
|
end
|
98
103
|
|
104
|
+
def exception_if_present
|
105
|
+
return "" unless ex = @request&.env&.[]("action_dispatch.exception")
|
106
|
+
"\n\nException while processing request: #{Minitest::UnexpectedError.new(ex).message}\n"
|
107
|
+
end
|
108
|
+
|
99
109
|
def location_if_redirected
|
100
110
|
return "" unless @response.redirection? && @response.location.present?
|
101
111
|
location = normalize_argument_to_redirection(@response.location)
|
@@ -118,9 +118,9 @@ module ActionDispatch
|
|
118
118
|
# assert_equal "/users", users_path
|
119
119
|
# end
|
120
120
|
#
|
121
|
-
def with_routing(&block)
|
121
|
+
def with_routing(config = nil, &block)
|
122
122
|
old_routes, old_controller = @routes, @controller
|
123
|
-
create_routes(&block)
|
123
|
+
create_routes(config, &block)
|
124
124
|
ensure
|
125
125
|
reset_routes(old_routes, old_controller)
|
126
126
|
end
|
@@ -267,8 +267,8 @@ module ActionDispatch
|
|
267
267
|
end
|
268
268
|
|
269
269
|
private
|
270
|
-
def create_routes
|
271
|
-
@routes = ActionDispatch::Routing::RouteSet.new
|
270
|
+
def create_routes(config = nil)
|
271
|
+
@routes = ActionDispatch::Routing::RouteSet.new(config || ActionDispatch::Routing::RouteSet::DEFAULT_CONFIG)
|
272
272
|
if @controller
|
273
273
|
@controller = @controller.clone
|
274
274
|
_routes = @routes
|
@@ -284,7 +284,17 @@ module ActionDispatch
|
|
284
284
|
|
285
285
|
# NOTE: rack-test v0.5 doesn't build a default uri correctly Make sure requested
|
286
286
|
# path is always a full URI.
|
287
|
-
|
287
|
+
uri = build_full_uri(path, request_env)
|
288
|
+
|
289
|
+
if method == :get && String === request_env[:params]
|
290
|
+
# rack-test will needlessly parse and rebuild a :params
|
291
|
+
# querystring, using Rack's query parser. At best that's a
|
292
|
+
# waste of time; at worst it can change the value.
|
293
|
+
|
294
|
+
uri << "?" << request_env.delete(:params)
|
295
|
+
end
|
296
|
+
|
297
|
+
session.request(uri, request_env)
|
288
298
|
|
289
299
|
@request_count += 1
|
290
300
|
@request = ActionDispatch::Request.new(session.last_request.env)
|
data/lib/action_dispatch.rb
CHANGED
@@ -53,7 +53,13 @@ module ActionDispatch
|
|
53
53
|
eager_autoload do
|
54
54
|
autoload_under "http" do
|
55
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"
|
56
61
|
autoload :PermissionsPolicy
|
62
|
+
autoload :QueryParser
|
57
63
|
autoload :Request
|
58
64
|
autoload :Response
|
59
65
|
end
|