actionpack 5.2.4 → 6.0.2.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +200 -317
- data/MIT-LICENSE +1 -1
- data/README.rdoc +3 -2
- data/lib/abstract_controller/base.rb +4 -2
- data/lib/abstract_controller/caching/fragments.rb +6 -22
- data/lib/abstract_controller/callbacks.rb +12 -0
- data/lib/abstract_controller/collector.rb +1 -1
- data/lib/abstract_controller/helpers.rb +2 -2
- data/lib/abstract_controller/railties/routes_helpers.rb +1 -1
- data/lib/abstract_controller/translation.rb +1 -0
- data/lib/action_controller.rb +5 -1
- data/lib/action_controller/api.rb +2 -1
- data/lib/action_controller/base.rb +2 -7
- data/lib/action_controller/caching.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +8 -5
- data/lib/action_controller/metal.rb +1 -1
- data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
- data/lib/action_controller/metal/conditional_get.rb +9 -3
- data/lib/action_controller/metal/data_streaming.rb +5 -6
- data/lib/action_controller/metal/default_headers.rb +17 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +1 -1
- data/lib/action_controller/metal/exceptions.rb +23 -2
- data/lib/action_controller/metal/flash.rb +5 -5
- data/lib/action_controller/metal/force_ssl.rb +15 -56
- data/lib/action_controller/metal/head.rb +1 -1
- data/lib/action_controller/metal/helpers.rb +3 -4
- data/lib/action_controller/metal/http_authentication.rb +20 -21
- data/lib/action_controller/metal/implicit_render.rb +4 -14
- data/lib/action_controller/metal/instrumentation.rb +3 -5
- data/lib/action_controller/metal/live.rb +29 -27
- data/lib/action_controller/metal/mime_responds.rb +13 -2
- data/lib/action_controller/metal/params_wrapper.rb +17 -13
- data/lib/action_controller/metal/redirecting.rb +5 -5
- data/lib/action_controller/metal/renderers.rb +4 -4
- data/lib/action_controller/metal/rendering.rb +2 -2
- data/lib/action_controller/metal/request_forgery_protection.rb +23 -12
- data/lib/action_controller/metal/strong_parameters.rb +63 -44
- data/lib/action_controller/metal/url_for.rb +1 -1
- data/lib/action_controller/railties/helpers.rb +1 -1
- data/lib/action_controller/renderer.rb +16 -3
- data/lib/action_controller/template_assertions.rb +1 -1
- data/lib/action_controller/test_case.rb +2 -5
- data/lib/action_dispatch.rb +9 -6
- data/lib/action_dispatch/http/cache.rb +14 -10
- data/lib/action_dispatch/http/content_disposition.rb +45 -0
- data/lib/action_dispatch/http/content_security_policy.rb +28 -16
- data/lib/action_dispatch/http/filter_parameters.rb +8 -6
- data/lib/action_dispatch/http/filter_redirect.rb +1 -1
- data/lib/action_dispatch/http/headers.rb +1 -1
- data/lib/action_dispatch/http/mime_negotiation.rb +7 -5
- data/lib/action_dispatch/http/mime_type.rb +14 -6
- data/lib/action_dispatch/http/parameter_filter.rb +5 -79
- data/lib/action_dispatch/http/parameters.rb +13 -3
- data/lib/action_dispatch/http/request.rb +10 -13
- data/lib/action_dispatch/http/response.rb +40 -20
- data/lib/action_dispatch/http/upload.rb +9 -1
- data/lib/action_dispatch/http/url.rb +81 -81
- data/lib/action_dispatch/journey/formatter.rb +2 -2
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -2
- data/lib/action_dispatch/journey/nodes/node.rb +9 -8
- data/lib/action_dispatch/journey/path/pattern.rb +6 -2
- data/lib/action_dispatch/journey/route.rb +5 -4
- data/lib/action_dispatch/journey/router.rb +0 -3
- data/lib/action_dispatch/journey/router/utils.rb +10 -10
- data/lib/action_dispatch/journey/routes.rb +0 -1
- data/lib/action_dispatch/journey/scanner.rb +11 -4
- data/lib/action_dispatch/journey/visitors.rb +1 -1
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +39 -0
- data/lib/action_dispatch/middleware/callbacks.rb +2 -4
- data/lib/action_dispatch/middleware/cookies.rb +52 -74
- data/lib/action_dispatch/middleware/debug_exceptions.rb +39 -59
- data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
- data/lib/action_dispatch/middleware/debug_view.rb +68 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +49 -15
- data/lib/action_dispatch/middleware/flash.rb +1 -1
- data/lib/action_dispatch/middleware/host_authorization.rb +103 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +6 -2
- data/lib/action_dispatch/middleware/remote_ip.rb +9 -11
- data/lib/action_dispatch/middleware/request_id.rb +2 -2
- data/lib/action_dispatch/middleware/session/abstract_store.rb +14 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +11 -6
- data/lib/action_dispatch/middleware/session/cookie_store.rb +18 -13
- data/lib/action_dispatch/middleware/show_exceptions.rb +1 -1
- data/lib/action_dispatch/middleware/ssl.rb +8 -8
- data/lib/action_dispatch/middleware/stack.rb +33 -1
- data/lib/action_dispatch/middleware/static.rb +5 -6
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
- data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +3 -1
- data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +26 -4
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +7 -4
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +4 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +3 -0
- data/lib/action_dispatch/railtie.rb +7 -2
- data/lib/action_dispatch/request/session.rb +15 -1
- data/lib/action_dispatch/routing.rb +21 -20
- data/lib/action_dispatch/routing/inspector.rb +99 -50
- data/lib/action_dispatch/routing/mapper.rb +61 -39
- data/lib/action_dispatch/routing/polymorphic_routes.rb +3 -4
- data/lib/action_dispatch/routing/route_set.rb +24 -27
- data/lib/action_dispatch/routing/url_for.rb +1 -0
- data/lib/action_dispatch/system_test_case.rb +44 -5
- data/lib/action_dispatch/system_testing/browser.rb +38 -7
- data/lib/action_dispatch/system_testing/driver.rb +10 -1
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +6 -5
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +7 -6
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +2 -3
- data/lib/action_dispatch/testing/assertions/routing.rb +15 -3
- data/lib/action_dispatch/testing/integration.rb +12 -5
- data/lib/action_dispatch/testing/request_encoder.rb +2 -2
- data/lib/action_dispatch/testing/test_process.rb +2 -2
- data/lib/action_dispatch/testing/test_response.rb +4 -32
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/gem_version.rb +4 -4
- metadata +34 -15
- data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
@@ -50,7 +50,19 @@ module ActionDispatch
|
|
50
50
|
|
51
51
|
private
|
52
52
|
def constraint_args(constraint, request)
|
53
|
-
|
53
|
+
arity = if constraint.respond_to?(:arity)
|
54
|
+
constraint.arity
|
55
|
+
else
|
56
|
+
constraint.method(:call).arity
|
57
|
+
end
|
58
|
+
|
59
|
+
if arity < 1
|
60
|
+
[]
|
61
|
+
elsif arity == 1
|
62
|
+
[request]
|
63
|
+
else
|
64
|
+
[request.path_parameters, request]
|
65
|
+
end
|
54
66
|
end
|
55
67
|
end
|
56
68
|
|
@@ -58,17 +70,17 @@ module ActionDispatch
|
|
58
70
|
ANCHOR_CHARACTERS_REGEX = %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z}
|
59
71
|
OPTIONAL_FORMAT_REGEX = %r{(?:\(\.:format\)+|\.:format|/)\Z}
|
60
72
|
|
61
|
-
attr_reader :requirements, :defaults
|
62
|
-
|
63
|
-
attr_reader :required_defaults, :ast
|
73
|
+
attr_reader :requirements, :defaults, :to, :default_controller,
|
74
|
+
:default_action, :required_defaults, :ast, :scope_options
|
64
75
|
|
65
76
|
def self.build(scope, set, ast, controller, default_action, to, via, formatted, options_constraints, anchor, options)
|
66
77
|
options = scope[:options].merge(options) if scope[:options]
|
67
78
|
|
68
79
|
defaults = (scope[:defaults] || {}).dup
|
69
80
|
scope_constraints = scope[:constraints] || {}
|
81
|
+
scope_options = scope[:options] || {}
|
70
82
|
|
71
|
-
new set, ast, defaults, controller, default_action, scope[:module], to, formatted, scope_constraints, scope[:blocks] || [], via, options_constraints, anchor, options
|
83
|
+
new set, ast, defaults, controller, default_action, scope[:module], to, formatted, scope_constraints, scope_options, scope[:blocks] || [], via, options_constraints, anchor, options
|
72
84
|
end
|
73
85
|
|
74
86
|
def self.check_via(via)
|
@@ -99,17 +111,18 @@ module ActionDispatch
|
|
99
111
|
format != false && path !~ OPTIONAL_FORMAT_REGEX
|
100
112
|
end
|
101
113
|
|
102
|
-
def initialize(set, ast, defaults, controller, default_action, modyoule, to, formatted, scope_constraints, blocks, via, options_constraints, anchor, options)
|
114
|
+
def initialize(set, ast, defaults, controller, default_action, modyoule, to, formatted, scope_constraints, scope_options, blocks, via, options_constraints, anchor, options)
|
103
115
|
@defaults = defaults
|
104
116
|
@set = set
|
105
117
|
|
106
|
-
@to = to
|
107
|
-
@default_controller = controller
|
108
|
-
@default_action = default_action
|
118
|
+
@to = intern(to)
|
119
|
+
@default_controller = intern(controller)
|
120
|
+
@default_action = intern(default_action)
|
109
121
|
@ast = ast
|
110
122
|
@anchor = anchor
|
111
123
|
@via = via
|
112
124
|
@internal = options.delete(:internal)
|
125
|
+
@scope_options = scope_options
|
113
126
|
|
114
127
|
path_params = ast.find_all(&:symbol?).map(&:to_sym)
|
115
128
|
|
@@ -148,17 +161,8 @@ module ActionDispatch
|
|
148
161
|
end
|
149
162
|
|
150
163
|
def make_route(name, precedence)
|
151
|
-
|
152
|
-
|
153
|
-
path,
|
154
|
-
conditions,
|
155
|
-
required_defaults,
|
156
|
-
defaults,
|
157
|
-
request_method,
|
158
|
-
precedence,
|
159
|
-
@internal)
|
160
|
-
|
161
|
-
route
|
164
|
+
Journey::Route.new(name, application, path, conditions, required_defaults,
|
165
|
+
defaults, request_method, precedence, scope_options, @internal)
|
162
166
|
end
|
163
167
|
|
164
168
|
def application
|
@@ -219,6 +223,10 @@ module ActionDispatch
|
|
219
223
|
private :build_path
|
220
224
|
|
221
225
|
private
|
226
|
+
def intern(object)
|
227
|
+
object.is_a?(String) ? -object : object
|
228
|
+
end
|
229
|
+
|
222
230
|
def add_wildcard_options(options, formatted, path_ast)
|
223
231
|
# Add a constraint for wildcard route to make it non-greedy and match the
|
224
232
|
# optional format part of the route by default.
|
@@ -279,7 +287,7 @@ module ActionDispatch
|
|
279
287
|
|
280
288
|
def verify_regexp_requirements(requirements)
|
281
289
|
requirements.each do |requirement|
|
282
|
-
if requirement.source
|
290
|
+
if ANCHOR_CHARACTERS_REGEX.match?(requirement.source)
|
283
291
|
raise ArgumentError, "Regexp anchor characters are not allowed in routing requirements: #{requirement.inspect}"
|
284
292
|
end
|
285
293
|
|
@@ -308,8 +316,8 @@ module ActionDispatch
|
|
308
316
|
def check_controller_and_action(path_params, controller, action)
|
309
317
|
hash = check_part(:controller, controller, path_params, {}) do |part|
|
310
318
|
translate_controller(part) {
|
311
|
-
message = "'#{part}' is not a supported controller name. This can lead to potential routing problems."
|
312
|
-
message << " See
|
319
|
+
message = +"'#{part}' is not a supported controller name. This can lead to potential routing problems."
|
320
|
+
message << " See https://guides.rubyonrails.org/routing.html#specifying-a-controller-to-use"
|
313
321
|
|
314
322
|
raise ArgumentError, message
|
315
323
|
}
|
@@ -333,7 +341,7 @@ module ActionDispatch
|
|
333
341
|
end
|
334
342
|
|
335
343
|
def split_to(to)
|
336
|
-
if to
|
344
|
+
if /#/.match?(to)
|
337
345
|
to.split("#")
|
338
346
|
else
|
339
347
|
[]
|
@@ -342,7 +350,7 @@ module ActionDispatch
|
|
342
350
|
|
343
351
|
def add_controller_module(controller, modyoule)
|
344
352
|
if modyoule && !controller.is_a?(Regexp)
|
345
|
-
if
|
353
|
+
if %r{\A/}.match?(controller)
|
346
354
|
controller[1..-1]
|
347
355
|
else
|
348
356
|
[modyoule, controller].compact.join("/")
|
@@ -553,10 +561,10 @@ module ActionDispatch
|
|
553
561
|
#
|
554
562
|
# match 'json_only', constraints: { format: 'json' }, via: :get
|
555
563
|
#
|
556
|
-
# class
|
564
|
+
# class PermitList
|
557
565
|
# def matches?(request) request.remote_ip == '1.2.3.4' end
|
558
566
|
# end
|
559
|
-
# match 'path', to: 'c#a', constraints:
|
567
|
+
# match 'path', to: 'c#a', constraints: PermitList.new, via: :get
|
560
568
|
#
|
561
569
|
# See <tt>Scoping#constraints</tt> for more examples with its scope
|
562
570
|
# equivalent.
|
@@ -611,7 +619,7 @@ module ActionDispatch
|
|
611
619
|
end
|
612
620
|
|
613
621
|
raise ArgumentError, "A rack application must be specified" unless app.respond_to?(:call)
|
614
|
-
raise ArgumentError,
|
622
|
+
raise ArgumentError, <<~MSG unless path
|
615
623
|
Must be called with mount point
|
616
624
|
|
617
625
|
mount SomeRackApp, at: "some_route"
|
@@ -644,7 +652,7 @@ module ActionDispatch
|
|
644
652
|
|
645
653
|
# Query if the following named route was already defined.
|
646
654
|
def has_named_route?(name)
|
647
|
-
@set.named_routes.key?
|
655
|
+
@set.named_routes.key?(name)
|
648
656
|
end
|
649
657
|
|
650
658
|
private
|
@@ -668,7 +676,7 @@ module ActionDispatch
|
|
668
676
|
|
669
677
|
script_namer = ->(options) do
|
670
678
|
prefix_options = options.slice(*_route.segment_keys)
|
671
|
-
prefix_options[:relative_url_root] = ""
|
679
|
+
prefix_options[:relative_url_root] = ""
|
672
680
|
|
673
681
|
if options[:_recall]
|
674
682
|
prefix_options.reverse_merge!(options[:_recall].slice(*_route.segment_keys))
|
@@ -1138,6 +1146,10 @@ module ActionDispatch
|
|
1138
1146
|
attr_reader :controller, :path, :param
|
1139
1147
|
|
1140
1148
|
def initialize(entities, api_only, shallow, options = {})
|
1149
|
+
if options[:param].to_s.include?(":")
|
1150
|
+
raise ArgumentError, ":param option can't contain colons"
|
1151
|
+
end
|
1152
|
+
|
1141
1153
|
@name = entities.to_s
|
1142
1154
|
@path = (options[:path] || @name).to_s
|
1143
1155
|
@controller = (options[:controller] || @name).to_s
|
@@ -1159,10 +1171,16 @@ module ActionDispatch
|
|
1159
1171
|
end
|
1160
1172
|
|
1161
1173
|
def actions
|
1174
|
+
if @except
|
1175
|
+
available_actions - Array(@except).map(&:to_sym)
|
1176
|
+
else
|
1177
|
+
available_actions
|
1178
|
+
end
|
1179
|
+
end
|
1180
|
+
|
1181
|
+
def available_actions
|
1162
1182
|
if @only
|
1163
1183
|
Array(@only).map(&:to_sym)
|
1164
|
-
elsif @except
|
1165
|
-
default_actions - Array(@except).map(&:to_sym)
|
1166
1184
|
else
|
1167
1185
|
default_actions
|
1168
1186
|
end
|
@@ -1389,6 +1407,8 @@ module ActionDispatch
|
|
1389
1407
|
# as a comment on a blog post like <tt>/posts/a-long-permalink/comments/1234</tt>
|
1390
1408
|
# to be shortened to just <tt>/comments/1234</tt>.
|
1391
1409
|
#
|
1410
|
+
# Set <tt>shallow: false</tt> on a child resource to ignore a parent's shallow parameter.
|
1411
|
+
#
|
1392
1412
|
# [:shallow_path]
|
1393
1413
|
# Prefixes nested shallow routes with the specified path.
|
1394
1414
|
#
|
@@ -1431,6 +1451,9 @@ module ActionDispatch
|
|
1431
1451
|
# Allows you to specify the default value for optional +format+
|
1432
1452
|
# segment or disable it by supplying +false+.
|
1433
1453
|
#
|
1454
|
+
# [:param]
|
1455
|
+
# Allows you to override the default param name of +:id+ in the URL.
|
1456
|
+
#
|
1434
1457
|
# === Examples
|
1435
1458
|
#
|
1436
1459
|
# # routes call <tt>Admin::PostsController</tt>
|
@@ -1588,7 +1611,7 @@ module ActionDispatch
|
|
1588
1611
|
when Symbol
|
1589
1612
|
options[:action] = to
|
1590
1613
|
when String
|
1591
|
-
if to
|
1614
|
+
if /#/.match?(to)
|
1592
1615
|
options[:to] = to
|
1593
1616
|
else
|
1594
1617
|
options[:controller] = to
|
@@ -1656,7 +1679,8 @@ module ActionDispatch
|
|
1656
1679
|
return true
|
1657
1680
|
end
|
1658
1681
|
|
1659
|
-
if options
|
1682
|
+
if options[:shallow]
|
1683
|
+
options.delete(:shallow)
|
1660
1684
|
shallow do
|
1661
1685
|
send(method, resources.pop, options, &block)
|
1662
1686
|
end
|
@@ -1914,7 +1938,7 @@ module ActionDispatch
|
|
1914
1938
|
|
1915
1939
|
default_action = options.delete(:action) || @scope[:action]
|
1916
1940
|
|
1917
|
-
if
|
1941
|
+
if /^[\w\-\/]+$/.match?(action)
|
1918
1942
|
default_action ||= action.tr("-", "_") unless action.include?("/")
|
1919
1943
|
else
|
1920
1944
|
action = nil
|
@@ -1934,9 +1958,7 @@ module ActionDispatch
|
|
1934
1958
|
end
|
1935
1959
|
|
1936
1960
|
def match_root_route(options)
|
1937
|
-
|
1938
|
-
args = ["/", { as: name, via: :get }.merge!(options)]
|
1939
|
-
|
1961
|
+
args = ["/", { as: :root, via: :get }.merge(options)]
|
1940
1962
|
match(*args)
|
1941
1963
|
end
|
1942
1964
|
end
|
@@ -2052,7 +2074,7 @@ module ActionDispatch
|
|
2052
2074
|
# of routing helpers, e.g:
|
2053
2075
|
#
|
2054
2076
|
# direct :homepage do
|
2055
|
-
# "
|
2077
|
+
# "https://rubyonrails.org"
|
2056
2078
|
# end
|
2057
2079
|
#
|
2058
2080
|
# direct :commentable do |model|
|
@@ -120,8 +120,7 @@ module ActionDispatch
|
|
120
120
|
opts
|
121
121
|
end
|
122
122
|
|
123
|
-
# Returns the path component of a URL for the given record.
|
124
|
-
# <tt>polymorphic_url</tt> with <tt>routing_type: :path</tt>.
|
123
|
+
# Returns the path component of a URL for the given record.
|
125
124
|
def polymorphic_path(record_or_hash_or_array, options = {})
|
126
125
|
if Hash === record_or_hash_or_array
|
127
126
|
options = record_or_hash_or_array.merge(options)
|
@@ -182,8 +181,8 @@ module ActionDispatch
|
|
182
181
|
CACHE[type].fetch(action) { build action, type }
|
183
182
|
end
|
184
183
|
|
185
|
-
def self.url; CACHE["url"
|
186
|
-
def self.path; CACHE["path"
|
184
|
+
def self.url; CACHE["url"][nil]; end
|
185
|
+
def self.path; CACHE["path"][nil]; end
|
187
186
|
|
188
187
|
def self.build(action, type)
|
189
188
|
prefix = action ? "#{action}_" : ""
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require "action_dispatch/journey"
|
4
4
|
require "active_support/core_ext/object/to_query"
|
5
|
-
require "active_support/core_ext/hash/slice"
|
6
5
|
require "active_support/core_ext/module/redefine_method"
|
7
6
|
require "active_support/core_ext/module/remove_method"
|
8
7
|
require "active_support/core_ext/array/extract_options"
|
@@ -36,7 +35,7 @@ module ActionDispatch
|
|
36
35
|
if @raise_on_name_error
|
37
36
|
raise
|
38
37
|
else
|
39
|
-
|
38
|
+
[404, { "X-Cascade" => "pass" }, []]
|
40
39
|
end
|
41
40
|
end
|
42
41
|
|
@@ -91,11 +90,11 @@ module ActionDispatch
|
|
91
90
|
|
92
91
|
def clear!
|
93
92
|
@path_helpers.each do |helper|
|
94
|
-
@path_helpers_module.
|
93
|
+
@path_helpers_module.remove_method helper
|
95
94
|
end
|
96
95
|
|
97
96
|
@url_helpers.each do |helper|
|
98
|
-
@url_helpers_module.
|
97
|
+
@url_helpers_module.remove_method helper
|
99
98
|
end
|
100
99
|
|
101
100
|
@routes.clear
|
@@ -109,8 +108,8 @@ module ActionDispatch
|
|
109
108
|
url_name = :"#{name}_url"
|
110
109
|
|
111
110
|
if routes.key? key
|
112
|
-
@path_helpers_module.
|
113
|
-
@url_helpers_module.
|
111
|
+
@path_helpers_module.undef_method path_name
|
112
|
+
@url_helpers_module.undef_method url_name
|
114
113
|
end
|
115
114
|
routes[key] = route
|
116
115
|
define_url_helper @path_helpers_module, route, path_name, route.defaults, name, PATH
|
@@ -154,13 +153,13 @@ module ActionDispatch
|
|
154
153
|
url_name = :"#{name}_url"
|
155
154
|
|
156
155
|
@path_helpers_module.module_eval do
|
157
|
-
|
156
|
+
redefine_method(path_name) do |*args|
|
158
157
|
helper.call(self, args, true)
|
159
158
|
end
|
160
159
|
end
|
161
160
|
|
162
161
|
@url_helpers_module.module_eval do
|
163
|
-
|
162
|
+
redefine_method(url_name) do |*args|
|
164
163
|
helper.call(self, args, false)
|
165
164
|
end
|
166
165
|
end
|
@@ -246,7 +245,7 @@ module ActionDispatch
|
|
246
245
|
missing_keys << missing_key
|
247
246
|
}
|
248
247
|
constraints = Hash[@route.requirements.merge(params).sort_by { |k, v| k.to_s }]
|
249
|
-
message = "No route matches #{constraints.inspect}"
|
248
|
+
message = +"No route matches #{constraints.inspect}"
|
250
249
|
message << ", missing required keys: #{missing_keys.sort.inspect}"
|
251
250
|
|
252
251
|
raise ActionController::UrlGenerationError, message
|
@@ -318,23 +317,21 @@ module ActionDispatch
|
|
318
317
|
#
|
319
318
|
def define_url_helper(mod, route, name, opts, route_key, url_strategy)
|
320
319
|
helper = UrlHelper.create(route, opts, route_key, url_strategy)
|
321
|
-
mod.
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
helper.call self, args, options
|
332
|
-
end
|
320
|
+
mod.define_method(name) do |*args|
|
321
|
+
last = args.last
|
322
|
+
options = \
|
323
|
+
case last
|
324
|
+
when Hash
|
325
|
+
args.pop
|
326
|
+
when ActionController::Parameters
|
327
|
+
args.pop.to_h
|
328
|
+
end
|
329
|
+
helper.call self, args, options
|
333
330
|
end
|
334
331
|
end
|
335
332
|
end
|
336
333
|
|
337
|
-
# strategy for building
|
334
|
+
# strategy for building URLs to send to the client
|
338
335
|
PATH = ->(options) { ActionDispatch::Http::URL.path_for(options) }
|
339
336
|
UNKNOWN = ->(options) { ActionDispatch::Http::URL.url_for(options) }
|
340
337
|
|
@@ -378,7 +375,7 @@ module ActionDispatch
|
|
378
375
|
@prepend = []
|
379
376
|
@disable_clear_and_finalize = false
|
380
377
|
@finalized = false
|
381
|
-
@env_key = "ROUTES_#{object_id}_SCRIPT_NAME"
|
378
|
+
@env_key = "ROUTES_#{object_id}_SCRIPT_NAME"
|
382
379
|
|
383
380
|
@set = Journey::Routes.new
|
384
381
|
@router = Journey::Router.new @set
|
@@ -585,7 +582,7 @@ module ActionDispatch
|
|
585
582
|
"You may have defined two routes with the same name using the `:as` option, or " \
|
586
583
|
"you may be overriding a route already defined by a resource with the same naming. " \
|
587
584
|
"For the latter, you can restrict the routes created with `resources` as explained here: \n" \
|
588
|
-
"
|
585
|
+
"https://guides.rubyonrails.org/routing.html#restricting-the-routes-created"
|
589
586
|
end
|
590
587
|
|
591
588
|
route = @set.add_route(name, mapping)
|
@@ -594,14 +591,14 @@ module ActionDispatch
|
|
594
591
|
if route.segment_keys.include?(:controller)
|
595
592
|
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
596
593
|
Using a dynamic :controller segment in a route is deprecated and
|
597
|
-
will be removed in Rails 6.
|
594
|
+
will be removed in Rails 6.1.
|
598
595
|
MSG
|
599
596
|
end
|
600
597
|
|
601
598
|
if route.segment_keys.include?(:action)
|
602
599
|
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
603
600
|
Using a dynamic :action segment in a route is deprecated and
|
604
|
-
will be removed in Rails 6.
|
601
|
+
will be removed in Rails 6.1.
|
605
602
|
MSG
|
606
603
|
end
|
607
604
|
|
@@ -730,7 +727,7 @@ module ActionDispatch
|
|
730
727
|
# Remove leading slashes from controllers
|
731
728
|
def normalize_controller!
|
732
729
|
if controller
|
733
|
-
if controller.start_with?("/"
|
730
|
+
if controller.start_with?("/")
|
734
731
|
@options[:controller] = controller[1..-1]
|
735
732
|
else
|
736
733
|
@options[:controller] = controller
|
@@ -133,6 +133,7 @@ module ActionDispatch
|
|
133
133
|
# <tt>ActionDispatch::Http::URL.tld_length</tt>, which in turn defaults to 1.
|
134
134
|
# * <tt>:port</tt> - Optionally specify the port to connect to.
|
135
135
|
# * <tt>:anchor</tt> - An anchor name to be appended to the path.
|
136
|
+
# * <tt>:params</tt> - The query parameters to be appended to the path.
|
136
137
|
# * <tt>:trailing_slash</tt> - If true, adds a trailing slash, as in "/archive/2009/"
|
137
138
|
# * <tt>:script_name</tt> - Specifies application path relative to domain root. If provided, prepends application path.
|
138
139
|
#
|
@@ -4,13 +4,13 @@ gem "capybara", ">= 2.15"
|
|
4
4
|
|
5
5
|
require "capybara/dsl"
|
6
6
|
require "capybara/minitest"
|
7
|
+
require "selenium/webdriver"
|
7
8
|
require "action_controller"
|
8
9
|
require "action_dispatch/system_testing/driver"
|
9
10
|
require "action_dispatch/system_testing/browser"
|
10
11
|
require "action_dispatch/system_testing/server"
|
11
12
|
require "action_dispatch/system_testing/test_helpers/screenshot_helper"
|
12
13
|
require "action_dispatch/system_testing/test_helpers/setup_and_teardown"
|
13
|
-
require "action_dispatch/system_testing/test_helpers/undef_methods"
|
14
14
|
|
15
15
|
module ActionDispatch
|
16
16
|
# = System Testing
|
@@ -89,19 +89,48 @@ module ActionDispatch
|
|
89
89
|
# { js_errors: true }
|
90
90
|
# end
|
91
91
|
#
|
92
|
+
# Some drivers require browser capabilities to be passed as a block instead
|
93
|
+
# of through the +options+ hash.
|
94
|
+
#
|
95
|
+
# As an example, if you want to add mobile emulation on chrome, you'll have to
|
96
|
+
# create an instance of selenium's +Chrome::Options+ object and add
|
97
|
+
# capabilities with a block.
|
98
|
+
#
|
99
|
+
# The block will be passed an instance of <tt><Driver>::Options</tt> where you can
|
100
|
+
# define the capabilities you want. Please refer to your driver documentation
|
101
|
+
# to learn about supported options.
|
102
|
+
#
|
103
|
+
# class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
|
104
|
+
# driven_by :selenium, using: :chrome, screen_size: [1024, 768] do |driver_option|
|
105
|
+
# driver_option.add_emulation(device_name: 'iPhone 6')
|
106
|
+
# driver_option.add_extension('path/to/chrome_extension.crx')
|
107
|
+
# end
|
108
|
+
# end
|
109
|
+
#
|
92
110
|
# Because <tt>ActionDispatch::SystemTestCase</tt> is a shim between Capybara
|
93
111
|
# and Rails, any driver that is supported by Capybara is supported by system
|
94
112
|
# tests as long as you include the required gems and files.
|
95
|
-
class SystemTestCase <
|
113
|
+
class SystemTestCase < ActiveSupport::TestCase
|
96
114
|
include Capybara::DSL
|
97
115
|
include Capybara::Minitest::Assertions
|
98
116
|
include SystemTesting::TestHelpers::SetupAndTeardown
|
99
117
|
include SystemTesting::TestHelpers::ScreenshotHelper
|
100
|
-
include SystemTesting::TestHelpers::UndefMethods
|
101
118
|
|
102
119
|
def initialize(*) # :nodoc:
|
103
120
|
super
|
104
121
|
self.class.driver.use
|
122
|
+
@proxy_route = if ActionDispatch.test_app
|
123
|
+
Class.new do
|
124
|
+
include ActionDispatch.test_app.routes.url_helpers
|
125
|
+
include ActionDispatch.test_app.routes.mounted_helpers
|
126
|
+
|
127
|
+
def url_options
|
128
|
+
default_url_options.merge(host: Capybara.app_host)
|
129
|
+
end
|
130
|
+
end.new
|
131
|
+
else
|
132
|
+
nil
|
133
|
+
end
|
105
134
|
end
|
106
135
|
|
107
136
|
def self.start_application # :nodoc:
|
@@ -134,12 +163,22 @@ module ActionDispatch
|
|
134
163
|
# driven_by :selenium, using: :firefox
|
135
164
|
#
|
136
165
|
# driven_by :selenium, using: :headless_firefox
|
137
|
-
def self.driven_by(driver, using: :chrome, screen_size: [1400, 1400], options: {})
|
138
|
-
|
166
|
+
def self.driven_by(driver, using: :chrome, screen_size: [1400, 1400], options: {}, &capabilities)
|
167
|
+
driver_options = { using: using, screen_size: screen_size, options: options }
|
168
|
+
|
169
|
+
self.driver = SystemTesting::Driver.new(driver, driver_options, &capabilities)
|
139
170
|
end
|
140
171
|
|
141
172
|
driven_by :selenium
|
142
173
|
|
174
|
+
def method_missing(method, *args, &block)
|
175
|
+
if @proxy_route.respond_to?(method)
|
176
|
+
@proxy_route.send(method, *args, &block)
|
177
|
+
else
|
178
|
+
super
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
143
182
|
ActiveSupport.run_load_hooks(:action_dispatch_system_test_case, self)
|
144
183
|
end
|
145
184
|
|