actionpack 5.2.8.1 → 6.1.6.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 +383 -346
- data/MIT-LICENSE +1 -2
- data/README.rdoc +4 -3
- data/lib/abstract_controller/base.rb +38 -4
- data/lib/abstract_controller/caching/fragments.rb +6 -22
- data/lib/abstract_controller/caching.rb +1 -1
- data/lib/abstract_controller/callbacks.rb +14 -2
- data/lib/abstract_controller/collector.rb +5 -4
- data/lib/abstract_controller/helpers.rb +106 -90
- data/lib/abstract_controller/railties/routes_helpers.rb +17 -1
- data/lib/abstract_controller/rendering.rb +9 -9
- data/lib/abstract_controller/translation.rb +11 -5
- data/lib/abstract_controller.rb +1 -0
- data/lib/action_controller/api.rb +4 -3
- data/lib/action_controller/base.rb +6 -9
- data/lib/action_controller/caching.rb +1 -3
- data/lib/action_controller/log_subscriber.rb +10 -7
- data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
- data/lib/action_controller/metal/conditional_get.rb +19 -5
- data/lib/action_controller/metal/content_security_policy.rb +1 -2
- data/lib/action_controller/metal/cookies.rb +3 -1
- data/lib/action_controller/metal/data_streaming.rb +6 -7
- data/lib/action_controller/metal/default_headers.rb +17 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +4 -6
- data/lib/action_controller/metal/exceptions.rb +56 -2
- data/lib/action_controller/metal/flash.rb +5 -5
- data/lib/action_controller/metal/head.rb +7 -4
- data/lib/action_controller/metal/helpers.rb +14 -5
- data/lib/action_controller/metal/http_authentication.rb +25 -23
- data/lib/action_controller/metal/implicit_render.rb +5 -15
- data/lib/action_controller/metal/instrumentation.rb +13 -14
- data/lib/action_controller/metal/live.rb +39 -32
- data/lib/action_controller/metal/logging.rb +20 -0
- data/lib/action_controller/metal/mime_responds.rb +19 -4
- data/lib/action_controller/metal/parameter_encoding.rb +35 -4
- data/lib/action_controller/metal/params_wrapper.rb +32 -22
- data/lib/action_controller/metal/permissions_policy.rb +46 -0
- data/lib/action_controller/metal/redirecting.rb +6 -6
- data/lib/action_controller/metal/renderers.rb +4 -4
- data/lib/action_controller/metal/rendering.rb +8 -3
- data/lib/action_controller/metal/request_forgery_protection.rb +26 -49
- data/lib/action_controller/metal/rescue.rb +1 -1
- data/lib/action_controller/metal/streaming.rb +0 -1
- data/lib/action_controller/metal/strong_parameters.rb +168 -59
- data/lib/action_controller/metal/url_for.rb +1 -1
- data/lib/action_controller/metal.rb +10 -8
- data/lib/action_controller/railties/helpers.rb +1 -1
- data/lib/action_controller/renderer.rb +37 -13
- data/lib/action_controller/template_assertions.rb +1 -1
- data/lib/action_controller/test_case.rb +71 -63
- data/lib/action_controller.rb +7 -4
- data/lib/action_dispatch/http/cache.rb +31 -27
- data/lib/action_dispatch/http/content_disposition.rb +45 -0
- data/lib/action_dispatch/http/content_security_policy.rb +34 -18
- data/lib/action_dispatch/http/filter_parameters.rb +9 -8
- data/lib/action_dispatch/http/filter_redirect.rb +2 -3
- data/lib/action_dispatch/http/headers.rb +4 -4
- data/lib/action_dispatch/http/mime_negotiation.rb +26 -13
- data/lib/action_dispatch/http/mime_type.rb +43 -24
- data/lib/action_dispatch/http/parameters.rb +14 -23
- data/lib/action_dispatch/http/permissions_policy.rb +173 -0
- data/lib/action_dispatch/http/request.rb +45 -22
- data/lib/action_dispatch/http/response.rb +45 -25
- data/lib/action_dispatch/http/upload.rb +9 -1
- data/lib/action_dispatch/http/url.rb +82 -82
- data/lib/action_dispatch/journey/formatter.rb +55 -31
- data/lib/action_dispatch/journey/gtg/builder.rb +22 -37
- data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
- data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -5
- data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
- data/lib/action_dispatch/journey/nodes/node.rb +13 -11
- data/lib/action_dispatch/journey/parser.rb +13 -13
- data/lib/action_dispatch/journey/parser.y +1 -1
- data/lib/action_dispatch/journey/path/pattern.rb +19 -21
- data/lib/action_dispatch/journey/route.rb +10 -20
- data/lib/action_dispatch/journey/router/utils.rb +14 -12
- data/lib/action_dispatch/journey/router.rb +26 -34
- data/lib/action_dispatch/journey/routes.rb +0 -2
- data/lib/action_dispatch/journey/scanner.rb +10 -4
- data/lib/action_dispatch/journey/visitors.rb +1 -4
- data/lib/action_dispatch/journey.rb +0 -2
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
- data/lib/action_dispatch/middleware/callbacks.rb +2 -4
- data/lib/action_dispatch/middleware/cookies.rb +128 -109
- data/lib/action_dispatch/middleware/debug_exceptions.rb +43 -66
- data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
- data/lib/action_dispatch/middleware/debug_view.rb +66 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +75 -30
- data/lib/action_dispatch/middleware/flash.rb +1 -1
- data/lib/action_dispatch/middleware/host_authorization.rb +170 -0
- data/lib/action_dispatch/middleware/public_exceptions.rb +6 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +14 -16
- data/lib/action_dispatch/middleware/request_id.rb +5 -6
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -3
- data/lib/action_dispatch/middleware/session/cookie_store.rb +3 -9
- data/lib/action_dispatch/middleware/show_exceptions.rb +13 -2
- data/lib/action_dispatch/middleware/ssl.rb +20 -15
- data/lib/action_dispatch/middleware/stack.rb +56 -2
- data/lib/action_dispatch/middleware/static.rb +153 -93
- 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/_message_and_suggestions.html.erb +22 -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 +23 -4
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +6 -3
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +4 -1
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +104 -8
- 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/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +24 -1
- data/lib/action_dispatch/railtie.rb +8 -2
- data/lib/action_dispatch/request/session.rb +11 -10
- data/lib/action_dispatch/request/utils.rb +26 -2
- data/lib/action_dispatch/routing/inspector.rb +100 -52
- data/lib/action_dispatch/routing/mapper.rb +155 -103
- data/lib/action_dispatch/routing/polymorphic_routes.rb +13 -15
- data/lib/action_dispatch/routing/redirection.rb +4 -4
- data/lib/action_dispatch/routing/route_set.rb +71 -69
- data/lib/action_dispatch/routing/url_for.rb +2 -2
- data/lib/action_dispatch/routing.rb +21 -20
- data/lib/action_dispatch/system_test_case.rb +60 -11
- data/lib/action_dispatch/system_testing/browser.rb +53 -16
- data/lib/action_dispatch/system_testing/driver.rb +11 -3
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +49 -7
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +8 -10
- data/lib/action_dispatch/testing/assertion_response.rb +0 -1
- data/lib/action_dispatch/testing/assertions/response.rb +4 -7
- data/lib/action_dispatch/testing/assertions/routing.rb +20 -8
- data/lib/action_dispatch/testing/assertions.rb +1 -1
- data/lib/action_dispatch/testing/integration.rb +60 -28
- data/lib/action_dispatch/testing/request_encoder.rb +2 -2
- data/lib/action_dispatch/testing/test_process.rb +32 -4
- data/lib/action_dispatch/testing/test_request.rb +3 -3
- data/lib/action_dispatch/testing/test_response.rb +4 -32
- data/lib/action_dispatch.rb +9 -3
- data/lib/action_pack/gem_version.rb +3 -3
- data/lib/action_pack.rb +1 -1
- metadata +34 -21
- data/lib/action_controller/metal/force_ssl.rb +0 -99
- data/lib/action_dispatch/http/parameter_filter.rb +0 -86
- data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -49
- data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -120
- data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
@@ -65,15 +65,15 @@ module ActionDispatch
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def escape(params)
|
68
|
-
|
68
|
+
params.transform_values { |v| Rack::Utils.escape(v) }
|
69
69
|
end
|
70
70
|
|
71
71
|
def escape_fragment(params)
|
72
|
-
|
72
|
+
params.transform_values { |v| Journey::Router::Utils.escape_fragment(v) }
|
73
73
|
end
|
74
74
|
|
75
75
|
def escape_path(params)
|
76
|
-
|
76
|
+
params.transform_values { |v| Journey::Router::Utils.escape_path(v) }
|
77
77
|
end
|
78
78
|
end
|
79
79
|
|
@@ -164,7 +164,7 @@ module ActionDispatch
|
|
164
164
|
# "http://#{request.host_with_port}/#{path}"
|
165
165
|
# }
|
166
166
|
#
|
167
|
-
# Note that the
|
167
|
+
# Note that the <tt>do end</tt> syntax for the redirect block wouldn't work, as Ruby would pass
|
168
168
|
# the block to +get+ instead of +redirect+. Use <tt>{ ... }</tt> instead.
|
169
169
|
#
|
170
170
|
# The options version of redirect allows you to supply only the parts of the URL which need
|
@@ -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,12 +35,11 @@ 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
|
|
43
42
|
private
|
44
|
-
|
45
43
|
def controller(req)
|
46
44
|
req.controller_class
|
47
45
|
rescue NameError => e
|
@@ -60,7 +58,6 @@ module ActionDispatch
|
|
60
58
|
end
|
61
59
|
|
62
60
|
private
|
63
|
-
|
64
61
|
def controller(_); @controller_class; end
|
65
62
|
end
|
66
63
|
|
@@ -91,11 +88,11 @@ module ActionDispatch
|
|
91
88
|
|
92
89
|
def clear!
|
93
90
|
@path_helpers.each do |helper|
|
94
|
-
@path_helpers_module.
|
91
|
+
@path_helpers_module.remove_method helper
|
95
92
|
end
|
96
93
|
|
97
94
|
@url_helpers.each do |helper|
|
98
|
-
@url_helpers_module.
|
95
|
+
@url_helpers_module.remove_method helper
|
99
96
|
end
|
100
97
|
|
101
98
|
@routes.clear
|
@@ -109,12 +106,14 @@ module ActionDispatch
|
|
109
106
|
url_name = :"#{name}_url"
|
110
107
|
|
111
108
|
if routes.key? key
|
112
|
-
@path_helpers_module.
|
113
|
-
@url_helpers_module.
|
109
|
+
@path_helpers_module.undef_method path_name
|
110
|
+
@url_helpers_module.undef_method url_name
|
114
111
|
end
|
115
112
|
routes[key] = route
|
116
|
-
|
117
|
-
|
113
|
+
|
114
|
+
helper = UrlHelper.create(route, route.defaults, name)
|
115
|
+
define_url_helper @path_helpers_module, path_name, helper, PATH
|
116
|
+
define_url_helper @url_helpers_module, url_name, helper, UNKNOWN
|
118
117
|
|
119
118
|
@path_helpers << path_name
|
120
119
|
@url_helpers << url_name
|
@@ -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
|
@@ -172,30 +171,30 @@ module ActionDispatch
|
|
172
171
|
end
|
173
172
|
|
174
173
|
class UrlHelper
|
175
|
-
def self.create(route, options, route_name
|
174
|
+
def self.create(route, options, route_name)
|
176
175
|
if optimize_helper?(route)
|
177
|
-
OptimizedUrlHelper.new(route, options, route_name
|
176
|
+
OptimizedUrlHelper.new(route, options, route_name)
|
178
177
|
else
|
179
|
-
new
|
178
|
+
new(route, options, route_name)
|
180
179
|
end
|
181
180
|
end
|
182
181
|
|
183
182
|
def self.optimize_helper?(route)
|
184
|
-
|
183
|
+
route.path.requirements.empty? && !route.glob?
|
185
184
|
end
|
186
185
|
|
187
|
-
attr_reader :
|
186
|
+
attr_reader :route_name
|
188
187
|
|
189
188
|
class OptimizedUrlHelper < UrlHelper
|
190
189
|
attr_reader :arg_size
|
191
190
|
|
192
|
-
def initialize(route, options, route_name
|
191
|
+
def initialize(route, options, route_name)
|
193
192
|
super
|
194
193
|
@required_parts = @route.required_parts
|
195
194
|
@arg_size = @required_parts.size
|
196
195
|
end
|
197
196
|
|
198
|
-
def call(t, args, inner_options)
|
197
|
+
def call(t, method_name, args, inner_options, url_strategy)
|
199
198
|
if args.size == arg_size && !inner_options && optimize_routes_generation?(t)
|
200
199
|
options = t.url_options.merge @options
|
201
200
|
options[:path] = optimized_helper(args)
|
@@ -216,7 +215,6 @@ module ActionDispatch
|
|
216
215
|
end
|
217
216
|
|
218
217
|
private
|
219
|
-
|
220
218
|
def optimized_helper(args)
|
221
219
|
params = parameterize_args(args) do
|
222
220
|
raise_generation_error(args)
|
@@ -246,22 +244,21 @@ module ActionDispatch
|
|
246
244
|
missing_keys << missing_key
|
247
245
|
}
|
248
246
|
constraints = Hash[@route.requirements.merge(params).sort_by { |k, v| k.to_s }]
|
249
|
-
message = "No route matches #{constraints.inspect}"
|
247
|
+
message = +"No route matches #{constraints.inspect}"
|
250
248
|
message << ", missing required keys: #{missing_keys.sort.inspect}"
|
251
249
|
|
252
250
|
raise ActionController::UrlGenerationError, message
|
253
251
|
end
|
254
252
|
end
|
255
253
|
|
256
|
-
def initialize(route, options, route_name
|
254
|
+
def initialize(route, options, route_name)
|
257
255
|
@options = options
|
258
256
|
@segment_keys = route.segment_keys.uniq
|
259
257
|
@route = route
|
260
|
-
@url_strategy = url_strategy
|
261
258
|
@route_name = route_name
|
262
259
|
end
|
263
260
|
|
264
|
-
def call(t, args, inner_options)
|
261
|
+
def call(t, method_name, args, inner_options, url_strategy)
|
265
262
|
controller_options = t.url_options
|
266
263
|
options = controller_options.merge @options
|
267
264
|
hash = handle_positional_args(controller_options,
|
@@ -270,7 +267,7 @@ module ActionDispatch
|
|
270
267
|
options,
|
271
268
|
@segment_keys)
|
272
269
|
|
273
|
-
t._routes.url_for(hash, route_name, url_strategy)
|
270
|
+
t._routes.url_for(hash, route_name, url_strategy, method_name)
|
274
271
|
end
|
275
272
|
|
276
273
|
def handle_positional_args(controller_options, inner_options, args, result, path_params)
|
@@ -316,31 +313,28 @@ module ActionDispatch
|
|
316
313
|
#
|
317
314
|
# foo_url(bar, baz, bang, sort_by: 'baz')
|
318
315
|
#
|
319
|
-
def define_url_helper(mod,
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
end
|
331
|
-
helper.call self, args, options
|
332
|
-
end
|
316
|
+
def define_url_helper(mod, name, helper, url_strategy)
|
317
|
+
mod.define_method(name) do |*args|
|
318
|
+
last = args.last
|
319
|
+
options = \
|
320
|
+
case last
|
321
|
+
when Hash
|
322
|
+
args.pop
|
323
|
+
when ActionController::Parameters
|
324
|
+
args.pop.to_h
|
325
|
+
end
|
326
|
+
helper.call(self, name, args, options, url_strategy)
|
333
327
|
end
|
334
328
|
end
|
335
329
|
end
|
336
330
|
|
337
|
-
# strategy for building
|
331
|
+
# strategy for building URLs to send to the client
|
338
332
|
PATH = ->(options) { ActionDispatch::Http::URL.path_for(options) }
|
339
333
|
UNKNOWN = ->(options) { ActionDispatch::Http::URL.url_for(options) }
|
340
334
|
|
341
335
|
attr_accessor :formatter, :set, :named_routes, :default_scope, :router
|
342
336
|
attr_accessor :disable_clear_and_finalize, :resources_path_names
|
343
|
-
attr_accessor :default_url_options
|
337
|
+
attr_accessor :default_url_options, :draw_paths
|
344
338
|
attr_reader :env_key, :polymorphic_mappings
|
345
339
|
|
346
340
|
alias :routes :set
|
@@ -372,13 +366,14 @@ module ActionDispatch
|
|
372
366
|
self.named_routes = NamedRouteCollection.new
|
373
367
|
self.resources_path_names = self.class.default_resources_path_names
|
374
368
|
self.default_url_options = {}
|
369
|
+
self.draw_paths = []
|
375
370
|
|
376
371
|
@config = config
|
377
372
|
@append = []
|
378
373
|
@prepend = []
|
379
374
|
@disable_clear_and_finalize = false
|
380
375
|
@finalized = false
|
381
|
-
@env_key = "ROUTES_#{object_id}_SCRIPT_NAME"
|
376
|
+
@env_key = "ROUTES_#{object_id}_SCRIPT_NAME"
|
382
377
|
|
383
378
|
@set = Journey::Routes.new
|
384
379
|
@router = Journey::Router.new @set
|
@@ -482,6 +477,14 @@ module ActionDispatch
|
|
482
477
|
end
|
483
478
|
|
484
479
|
def url_helpers(supports_path = true)
|
480
|
+
if supports_path
|
481
|
+
@url_helpers_with_paths ||= generate_url_helpers(true)
|
482
|
+
else
|
483
|
+
@url_helpers_without_paths ||= generate_url_helpers(false)
|
484
|
+
end
|
485
|
+
end
|
486
|
+
|
487
|
+
def generate_url_helpers(supports_path)
|
485
488
|
routes = self
|
486
489
|
|
487
490
|
Module.new do
|
@@ -585,7 +588,7 @@ module ActionDispatch
|
|
585
588
|
"You may have defined two routes with the same name using the `:as` option, or " \
|
586
589
|
"you may be overriding a route already defined by a resource with the same naming. " \
|
587
590
|
"For the latter, you can restrict the routes created with `resources` as explained here: \n" \
|
588
|
-
"
|
591
|
+
"https://guides.rubyonrails.org/routing.html#restricting-the-routes-created"
|
589
592
|
end
|
590
593
|
|
591
594
|
route = @set.add_route(name, mapping)
|
@@ -594,14 +597,14 @@ module ActionDispatch
|
|
594
597
|
if route.segment_keys.include?(:controller)
|
595
598
|
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
596
599
|
Using a dynamic :controller segment in a route is deprecated and
|
597
|
-
will be removed in Rails
|
600
|
+
will be removed in Rails 7.0.
|
598
601
|
MSG
|
599
602
|
end
|
600
603
|
|
601
604
|
if route.segment_keys.include?(:action)
|
602
605
|
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
603
606
|
Using a dynamic :action segment in a route is deprecated and
|
604
|
-
will be removed in Rails
|
607
|
+
will be removed in Rails 7.0.
|
605
608
|
MSG
|
606
609
|
end
|
607
610
|
|
@@ -647,14 +650,6 @@ module ActionDispatch
|
|
647
650
|
end
|
648
651
|
|
649
652
|
class Generator
|
650
|
-
PARAMETERIZE = lambda do |name, value|
|
651
|
-
if name == :controller
|
652
|
-
value
|
653
|
-
else
|
654
|
-
value.to_param
|
655
|
-
end
|
656
|
-
end
|
657
|
-
|
658
653
|
attr_reader :options, :recall, :set, :named_route
|
659
654
|
|
660
655
|
def initialize(named_route, options, recall, set)
|
@@ -730,7 +725,7 @@ module ActionDispatch
|
|
730
725
|
# Remove leading slashes from controllers
|
731
726
|
def normalize_controller!
|
732
727
|
if controller
|
733
|
-
if controller.start_with?("/"
|
728
|
+
if controller.start_with?("/")
|
734
729
|
@options[:controller] = controller[1..-1]
|
735
730
|
else
|
736
731
|
@options[:controller] = controller
|
@@ -738,10 +733,10 @@ module ActionDispatch
|
|
738
733
|
end
|
739
734
|
end
|
740
735
|
|
741
|
-
# Generates a path from routes, returns
|
742
|
-
#
|
736
|
+
# Generates a path from routes, returns a RouteWithParams or MissingRoute.
|
737
|
+
# MissingRoute will raise ActionController::UrlGenerationError.
|
743
738
|
def generate
|
744
|
-
@set.formatter.generate(named_route, options, recall
|
739
|
+
@set.formatter.generate(named_route, options, recall)
|
745
740
|
end
|
746
741
|
|
747
742
|
def different_controller?
|
@@ -766,13 +761,18 @@ module ActionDispatch
|
|
766
761
|
end
|
767
762
|
|
768
763
|
def generate_extras(options, recall = {})
|
769
|
-
|
770
|
-
|
771
|
-
|
764
|
+
if recall
|
765
|
+
options = options.merge(_recall: recall)
|
766
|
+
end
|
767
|
+
|
768
|
+
route_name = options.delete :use_route
|
769
|
+
generator = generate(route_name, options, recall)
|
770
|
+
path_info = path_for(options, route_name, [])
|
771
|
+
[URI(path_info).path, generator.params.except(:_recall).keys]
|
772
772
|
end
|
773
773
|
|
774
|
-
def generate(
|
775
|
-
Generator.new(
|
774
|
+
def generate(route_name, options, recall = {}, method_name = nil)
|
775
|
+
Generator.new(route_name, options, recall, self).generate
|
776
776
|
end
|
777
777
|
private :generate
|
778
778
|
|
@@ -792,12 +792,12 @@ module ActionDispatch
|
|
792
792
|
options.delete(:relative_url_root) || relative_url_root
|
793
793
|
end
|
794
794
|
|
795
|
-
def path_for(options, route_name = nil)
|
796
|
-
url_for(options, route_name, PATH)
|
795
|
+
def path_for(options, route_name = nil, reserved = RESERVED_OPTIONS)
|
796
|
+
url_for(options, route_name, PATH, nil, reserved)
|
797
797
|
end
|
798
798
|
|
799
799
|
# The +options+ argument must be a hash whose keys are *symbols*.
|
800
|
-
def url_for(options, route_name = nil, url_strategy = UNKNOWN)
|
800
|
+
def url_for(options, route_name = nil, url_strategy = UNKNOWN, method_name = nil, reserved = RESERVED_OPTIONS)
|
801
801
|
options = default_url_options.merge options
|
802
802
|
|
803
803
|
user = password = nil
|
@@ -817,9 +817,11 @@ module ActionDispatch
|
|
817
817
|
end
|
818
818
|
|
819
819
|
path_options = options.dup
|
820
|
-
|
820
|
+
reserved.each { |ro| path_options.delete ro }
|
821
821
|
|
822
|
-
|
822
|
+
route_with_params = generate(route_name, path_options, recall)
|
823
|
+
path = route_with_params.path(method_name)
|
824
|
+
params = route_with_params.params
|
823
825
|
|
824
826
|
if options.key? :params
|
825
827
|
params.merge! options[:params]
|
@@ -842,7 +844,7 @@ module ActionDispatch
|
|
842
844
|
|
843
845
|
def recognize_path(path, environment = {})
|
844
846
|
method = (environment[:method] || "GET").to_s.upcase
|
845
|
-
path = Journey::Router::Utils.normalize_path(path) unless
|
847
|
+
path = Journey::Router::Utils.normalize_path(path) unless %r{://}.match?(path)
|
846
848
|
extras = environment[:extras] || {}
|
847
849
|
|
848
850
|
begin
|
@@ -861,7 +863,7 @@ module ActionDispatch
|
|
861
863
|
params.each do |key, value|
|
862
864
|
if value.is_a?(String)
|
863
865
|
value = value.dup.force_encoding(Encoding::BINARY)
|
864
|
-
params[key] = URI.
|
866
|
+
params[key] = URI::DEFAULT_PARSER.unescape(value)
|
865
867
|
end
|
866
868
|
end
|
867
869
|
req.path_parameters = params
|
@@ -107,6 +107,7 @@ module ActionDispatch
|
|
107
107
|
@_routes = nil
|
108
108
|
super
|
109
109
|
end
|
110
|
+
ruby2_keywords(:initialize) if respond_to?(:ruby2_keywords, true)
|
110
111
|
|
111
112
|
# Hook overridden in controller to add request information
|
112
113
|
# with +default_url_options+. Application logic should not
|
@@ -133,6 +134,7 @@ module ActionDispatch
|
|
133
134
|
# <tt>ActionDispatch::Http::URL.tld_length</tt>, which in turn defaults to 1.
|
134
135
|
# * <tt>:port</tt> - Optionally specify the port to connect to.
|
135
136
|
# * <tt>:anchor</tt> - An anchor name to be appended to the path.
|
137
|
+
# * <tt>:params</tt> - The query parameters to be appended to the path.
|
136
138
|
# * <tt>:trailing_slash</tt> - If true, adds a trailing slash, as in "/archive/2009/"
|
137
139
|
# * <tt>:script_name</tt> - Specifies application path relative to domain root. If provided, prepends application path.
|
138
140
|
#
|
@@ -214,13 +216,11 @@ module ActionDispatch
|
|
214
216
|
end
|
215
217
|
|
216
218
|
protected
|
217
|
-
|
218
219
|
def optimize_routes_generation?
|
219
220
|
_routes.optimize_routes_generation? && default_url_options.empty?
|
220
221
|
end
|
221
222
|
|
222
223
|
private
|
223
|
-
|
224
224
|
def _with_routes(routes) # :doc:
|
225
225
|
old_routes, @_routes = @_routes, routes
|
226
226
|
yield
|
@@ -74,8 +74,8 @@ module ActionDispatch
|
|
74
74
|
# For routes that don't fit the <tt>resources</tt> mold, you can use the HTTP helper
|
75
75
|
# methods <tt>get</tt>, <tt>post</tt>, <tt>patch</tt>, <tt>put</tt> and <tt>delete</tt>.
|
76
76
|
#
|
77
|
-
# get 'post/:id'
|
78
|
-
# post 'post/:id'
|
77
|
+
# get 'post/:id', to: 'posts#show'
|
78
|
+
# post 'post/:id', to: 'posts#create_comment'
|
79
79
|
#
|
80
80
|
# Now, if you POST to <tt>/posts/:id</tt>, it will route to the <tt>create_comment</tt> action. A GET on the same
|
81
81
|
# URL will route to the <tt>show</tt> action.
|
@@ -83,7 +83,7 @@ module ActionDispatch
|
|
83
83
|
# If your route needs to respond to more than one HTTP method (or all methods) then using the
|
84
84
|
# <tt>:via</tt> option on <tt>match</tt> is preferable.
|
85
85
|
#
|
86
|
-
# match 'post/:id'
|
86
|
+
# match 'post/:id', to: 'posts#show', via: [:get, :post]
|
87
87
|
#
|
88
88
|
# == Named routes
|
89
89
|
#
|
@@ -94,7 +94,7 @@ module ActionDispatch
|
|
94
94
|
# Example:
|
95
95
|
#
|
96
96
|
# # In config/routes.rb
|
97
|
-
# get '/login'
|
97
|
+
# get '/login', to: 'accounts#login', as: 'login'
|
98
98
|
#
|
99
99
|
# # With render, redirect_to, tests, etc.
|
100
100
|
# redirect_to login_url
|
@@ -120,9 +120,9 @@ module ActionDispatch
|
|
120
120
|
#
|
121
121
|
# # In config/routes.rb
|
122
122
|
# controller :blog do
|
123
|
-
# get 'blog/show'
|
124
|
-
# get 'blog/delete'
|
125
|
-
# get 'blog/edit'
|
123
|
+
# get 'blog/show', to: :list
|
124
|
+
# get 'blog/delete', to: :delete
|
125
|
+
# get 'blog/edit', to: :edit
|
126
126
|
# end
|
127
127
|
#
|
128
128
|
# # provides named routes for show, delete, and edit
|
@@ -132,7 +132,7 @@ module ActionDispatch
|
|
132
132
|
#
|
133
133
|
# Routes can generate pretty URLs. For example:
|
134
134
|
#
|
135
|
-
# get '/articles/:year/:month/:day'
|
135
|
+
# get '/articles/:year/:month/:day', to: 'articles#find_by_id', constraints: {
|
136
136
|
# year: /\d{4}/,
|
137
137
|
# month: /\d{1,2}/,
|
138
138
|
# day: /\d{1,2}/
|
@@ -147,7 +147,7 @@ module ActionDispatch
|
|
147
147
|
# You can specify a regular expression to define a format for a parameter.
|
148
148
|
#
|
149
149
|
# controller 'geocode' do
|
150
|
-
# get 'geocode/:postalcode'
|
150
|
+
# get 'geocode/:postalcode', to: :show, constraints: {
|
151
151
|
# postalcode: /\d{5}(-\d{4})?/
|
152
152
|
# }
|
153
153
|
# end
|
@@ -156,13 +156,13 @@ module ActionDispatch
|
|
156
156
|
# expression modifiers:
|
157
157
|
#
|
158
158
|
# controller 'geocode' do
|
159
|
-
# get 'geocode/:postalcode'
|
159
|
+
# get 'geocode/:postalcode', to: :show, constraints: {
|
160
160
|
# postalcode: /hx\d\d\s\d[a-z]{2}/i
|
161
161
|
# }
|
162
162
|
# end
|
163
163
|
#
|
164
164
|
# controller 'geocode' do
|
165
|
-
# get 'geocode/:postalcode'
|
165
|
+
# get 'geocode/:postalcode', to: :show, constraints: {
|
166
166
|
# postalcode: /# Postalcode format
|
167
167
|
# \d{5} #Prefix
|
168
168
|
# (-\d{4})? #Suffix
|
@@ -178,13 +178,13 @@ module ActionDispatch
|
|
178
178
|
#
|
179
179
|
# You can redirect any path to another path using the redirect helper in your router:
|
180
180
|
#
|
181
|
-
# get "/stories"
|
181
|
+
# get "/stories", to: redirect("/posts")
|
182
182
|
#
|
183
183
|
# == Unicode character routes
|
184
184
|
#
|
185
185
|
# You can specify unicode character routes in your router:
|
186
186
|
#
|
187
|
-
# get "こんにちは"
|
187
|
+
# get "こんにちは", to: "welcome#index"
|
188
188
|
#
|
189
189
|
# == Routing to Rack Applications
|
190
190
|
#
|
@@ -192,7 +192,7 @@ module ActionDispatch
|
|
192
192
|
# index action in the PostsController, you can specify any Rack application
|
193
193
|
# as the endpoint for a matcher:
|
194
194
|
#
|
195
|
-
# get "/application.js"
|
195
|
+
# get "/application.js", to: Sprockets
|
196
196
|
#
|
197
197
|
# == Reloading routes
|
198
198
|
#
|
@@ -210,8 +210,8 @@ module ActionDispatch
|
|
210
210
|
# === +assert_routing+
|
211
211
|
#
|
212
212
|
# def test_movie_route_properly_splits
|
213
|
-
#
|
214
|
-
#
|
213
|
+
# opts = {controller: "plugin", action: "checkout", id: "2"}
|
214
|
+
# assert_routing "plugin/checkout/2", opts
|
215
215
|
# end
|
216
216
|
#
|
217
217
|
# +assert_routing+ lets you test whether or not the route properly resolves into options.
|
@@ -219,8 +219,8 @@ module ActionDispatch
|
|
219
219
|
# === +assert_recognizes+
|
220
220
|
#
|
221
221
|
# def test_route_has_options
|
222
|
-
#
|
223
|
-
#
|
222
|
+
# opts = {controller: "plugin", action: "show", id: "12"}
|
223
|
+
# assert_recognizes opts, "/plugins/show/12"
|
224
224
|
# end
|
225
225
|
#
|
226
226
|
# Note the subtle difference between the two: +assert_routing+ tests that
|
@@ -243,8 +243,9 @@ module ActionDispatch
|
|
243
243
|
#
|
244
244
|
# rails routes
|
245
245
|
#
|
246
|
-
# Target specific
|
247
|
-
#
|
246
|
+
# Target a specific controller with <tt>-c</tt>, or grep routes
|
247
|
+
# using <tt>-g</tt>. Useful in conjunction with <tt>--expanded</tt>
|
248
|
+
# which displays routes vertically.
|
248
249
|
module Routing
|
249
250
|
extend ActiveSupport::Autoload
|
250
251
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
gem "capybara", ">=
|
3
|
+
gem "capybara", ">= 3.26"
|
4
4
|
|
5
5
|
require "capybara/dsl"
|
6
6
|
require "capybara/minitest"
|
@@ -10,7 +10,6 @@ require "action_dispatch/system_testing/browser"
|
|
10
10
|
require "action_dispatch/system_testing/server"
|
11
11
|
require "action_dispatch/system_testing/test_helpers/screenshot_helper"
|
12
12
|
require "action_dispatch/system_testing/test_helpers/setup_and_teardown"
|
13
|
-
require "action_dispatch/system_testing/test_helpers/undef_methods"
|
14
13
|
|
15
14
|
module ActionDispatch
|
16
15
|
# = System Testing
|
@@ -27,7 +26,7 @@ module ActionDispatch
|
|
27
26
|
#
|
28
27
|
# Here is an example system test:
|
29
28
|
#
|
30
|
-
# require
|
29
|
+
# require "application_system_test_case"
|
31
30
|
#
|
32
31
|
# class Users::CreateTest < ApplicationSystemTestCase
|
33
32
|
# test "adding a new user" do
|
@@ -89,18 +88,38 @@ module ActionDispatch
|
|
89
88
|
# { js_errors: true }
|
90
89
|
# end
|
91
90
|
#
|
91
|
+
# Some drivers require browser capabilities to be passed as a block instead
|
92
|
+
# of through the +options+ hash.
|
93
|
+
#
|
94
|
+
# As an example, if you want to add mobile emulation on chrome, you'll have to
|
95
|
+
# create an instance of selenium's +Chrome::Options+ object and add
|
96
|
+
# capabilities with a block.
|
97
|
+
#
|
98
|
+
# The block will be passed an instance of <tt><Driver>::Options</tt> where you can
|
99
|
+
# define the capabilities you want. Please refer to your driver documentation
|
100
|
+
# to learn about supported options.
|
101
|
+
#
|
102
|
+
# class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
|
103
|
+
# driven_by :selenium, using: :chrome, screen_size: [1024, 768] do |driver_option|
|
104
|
+
# driver_option.add_emulation(device_name: 'iPhone 6')
|
105
|
+
# driver_option.add_extension('path/to/chrome_extension.crx')
|
106
|
+
# end
|
107
|
+
# end
|
108
|
+
#
|
92
109
|
# Because <tt>ActionDispatch::SystemTestCase</tt> is a shim between Capybara
|
93
110
|
# and Rails, any driver that is supported by Capybara is supported by system
|
94
111
|
# tests as long as you include the required gems and files.
|
95
|
-
class SystemTestCase <
|
112
|
+
class SystemTestCase < ActiveSupport::TestCase
|
96
113
|
include Capybara::DSL
|
97
114
|
include Capybara::Minitest::Assertions
|
98
115
|
include SystemTesting::TestHelpers::SetupAndTeardown
|
99
116
|
include SystemTesting::TestHelpers::ScreenshotHelper
|
100
|
-
|
117
|
+
|
118
|
+
DEFAULT_HOST = "http://127.0.0.1"
|
101
119
|
|
102
120
|
def initialize(*) # :nodoc:
|
103
121
|
super
|
122
|
+
self.class.driven_by(:selenium) unless self.class.driver?
|
104
123
|
self.class.driver.use
|
105
124
|
end
|
106
125
|
|
@@ -134,14 +153,44 @@ module ActionDispatch
|
|
134
153
|
# driven_by :selenium, using: :firefox
|
135
154
|
#
|
136
155
|
# driven_by :selenium, using: :headless_firefox
|
137
|
-
def self.driven_by(driver, using: :chrome, screen_size: [1400, 1400], options: {})
|
138
|
-
|
156
|
+
def self.driven_by(driver, using: :chrome, screen_size: [1400, 1400], options: {}, &capabilities)
|
157
|
+
driver_options = { using: using, screen_size: screen_size, options: options }
|
158
|
+
|
159
|
+
self.driver = SystemTesting::Driver.new(driver, **driver_options, &capabilities)
|
139
160
|
end
|
140
161
|
|
141
|
-
|
162
|
+
private
|
163
|
+
def url_helpers
|
164
|
+
@url_helpers ||=
|
165
|
+
if ActionDispatch.test_app
|
166
|
+
Class.new do
|
167
|
+
include ActionDispatch.test_app.routes.url_helpers
|
168
|
+
include ActionDispatch.test_app.routes.mounted_helpers
|
142
169
|
|
143
|
-
|
144
|
-
|
170
|
+
def url_options
|
171
|
+
default_url_options.reverse_merge(host: app_host)
|
172
|
+
end
|
173
|
+
|
174
|
+
def app_host
|
175
|
+
Capybara.app_host || Capybara.current_session.server_url || DEFAULT_HOST
|
176
|
+
end
|
177
|
+
end.new
|
178
|
+
end
|
179
|
+
end
|
145
180
|
|
146
|
-
|
181
|
+
def method_missing(name, *args, &block)
|
182
|
+
if url_helpers.respond_to?(name)
|
183
|
+
url_helpers.public_send(name, *args, &block)
|
184
|
+
else
|
185
|
+
super
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def respond_to_missing?(name, include_private = false)
|
190
|
+
url_helpers.respond_to?(name)
|
191
|
+
end
|
192
|
+
end
|
147
193
|
end
|
194
|
+
|
195
|
+
ActiveSupport.run_load_hooks :action_dispatch_system_test_case, ActionDispatch::SystemTestCase
|
196
|
+
ActionDispatch::SystemTestCase.start_application
|