actionpack 5.2.6 → 6.1.4.4

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.

Files changed (155) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +327 -335
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/abstract_controller/base.rb +38 -4
  6. data/lib/abstract_controller/caching/fragments.rb +6 -22
  7. data/lib/abstract_controller/caching.rb +1 -1
  8. data/lib/abstract_controller/callbacks.rb +14 -2
  9. data/lib/abstract_controller/collector.rb +1 -2
  10. data/lib/abstract_controller/helpers.rb +106 -90
  11. data/lib/abstract_controller/railties/routes_helpers.rb +17 -1
  12. data/lib/abstract_controller/rendering.rb +9 -9
  13. data/lib/abstract_controller/translation.rb +11 -5
  14. data/lib/abstract_controller.rb +1 -0
  15. data/lib/action_controller/api.rb +4 -3
  16. data/lib/action_controller/base.rb +6 -9
  17. data/lib/action_controller/caching.rb +1 -3
  18. data/lib/action_controller/log_subscriber.rb +10 -7
  19. data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
  20. data/lib/action_controller/metal/conditional_get.rb +19 -5
  21. data/lib/action_controller/metal/content_security_policy.rb +1 -2
  22. data/lib/action_controller/metal/cookies.rb +3 -1
  23. data/lib/action_controller/metal/data_streaming.rb +6 -7
  24. data/lib/action_controller/metal/default_headers.rb +17 -0
  25. data/lib/action_controller/metal/etag_with_template_digest.rb +4 -6
  26. data/lib/action_controller/metal/exceptions.rb +56 -2
  27. data/lib/action_controller/metal/flash.rb +5 -5
  28. data/lib/action_controller/metal/head.rb +7 -4
  29. data/lib/action_controller/metal/helpers.rb +14 -5
  30. data/lib/action_controller/metal/http_authentication.rb +24 -23
  31. data/lib/action_controller/metal/implicit_render.rb +5 -15
  32. data/lib/action_controller/metal/instrumentation.rb +13 -14
  33. data/lib/action_controller/metal/live.rb +39 -32
  34. data/lib/action_controller/metal/logging.rb +20 -0
  35. data/lib/action_controller/metal/mime_responds.rb +19 -4
  36. data/lib/action_controller/metal/parameter_encoding.rb +35 -4
  37. data/lib/action_controller/metal/params_wrapper.rb +32 -22
  38. data/lib/action_controller/metal/permissions_policy.rb +46 -0
  39. data/lib/action_controller/metal/redirecting.rb +6 -6
  40. data/lib/action_controller/metal/renderers.rb +4 -4
  41. data/lib/action_controller/metal/rendering.rb +8 -3
  42. data/lib/action_controller/metal/request_forgery_protection.rb +26 -49
  43. data/lib/action_controller/metal/rescue.rb +1 -1
  44. data/lib/action_controller/metal/streaming.rb +0 -1
  45. data/lib/action_controller/metal/strong_parameters.rb +167 -58
  46. data/lib/action_controller/metal/url_for.rb +1 -1
  47. data/lib/action_controller/metal.rb +10 -8
  48. data/lib/action_controller/railties/helpers.rb +1 -1
  49. data/lib/action_controller/renderer.rb +37 -13
  50. data/lib/action_controller/template_assertions.rb +1 -1
  51. data/lib/action_controller/test_case.rb +71 -63
  52. data/lib/action_controller.rb +7 -4
  53. data/lib/action_dispatch/http/cache.rb +31 -27
  54. data/lib/action_dispatch/http/content_disposition.rb +45 -0
  55. data/lib/action_dispatch/http/content_security_policy.rb +33 -19
  56. data/lib/action_dispatch/http/filter_parameters.rb +9 -8
  57. data/lib/action_dispatch/http/filter_redirect.rb +2 -3
  58. data/lib/action_dispatch/http/headers.rb +4 -4
  59. data/lib/action_dispatch/http/mime_negotiation.rb +26 -13
  60. data/lib/action_dispatch/http/mime_type.rb +43 -24
  61. data/lib/action_dispatch/http/parameters.rb +14 -23
  62. data/lib/action_dispatch/http/permissions_policy.rb +173 -0
  63. data/lib/action_dispatch/http/request.rb +45 -22
  64. data/lib/action_dispatch/http/response.rb +45 -25
  65. data/lib/action_dispatch/http/upload.rb +9 -1
  66. data/lib/action_dispatch/http/url.rb +82 -82
  67. data/lib/action_dispatch/journey/formatter.rb +55 -31
  68. data/lib/action_dispatch/journey/gtg/builder.rb +22 -37
  69. data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
  70. data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -5
  71. data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
  72. data/lib/action_dispatch/journey/nodes/node.rb +13 -11
  73. data/lib/action_dispatch/journey/parser.rb +13 -13
  74. data/lib/action_dispatch/journey/parser.y +1 -1
  75. data/lib/action_dispatch/journey/path/pattern.rb +19 -21
  76. data/lib/action_dispatch/journey/route.rb +10 -20
  77. data/lib/action_dispatch/journey/router/utils.rb +14 -12
  78. data/lib/action_dispatch/journey/router.rb +26 -34
  79. data/lib/action_dispatch/journey/routes.rb +0 -2
  80. data/lib/action_dispatch/journey/scanner.rb +10 -4
  81. data/lib/action_dispatch/journey/visitors.rb +1 -4
  82. data/lib/action_dispatch/journey.rb +0 -2
  83. data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
  84. data/lib/action_dispatch/middleware/callbacks.rb +2 -4
  85. data/lib/action_dispatch/middleware/cookies.rb +128 -109
  86. data/lib/action_dispatch/middleware/debug_exceptions.rb +43 -66
  87. data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
  88. data/lib/action_dispatch/middleware/debug_view.rb +66 -0
  89. data/lib/action_dispatch/middleware/exception_wrapper.rb +75 -30
  90. data/lib/action_dispatch/middleware/flash.rb +1 -1
  91. data/lib/action_dispatch/middleware/host_authorization.rb +141 -0
  92. data/lib/action_dispatch/middleware/public_exceptions.rb +6 -3
  93. data/lib/action_dispatch/middleware/remote_ip.rb +14 -16
  94. data/lib/action_dispatch/middleware/request_id.rb +5 -6
  95. data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -3
  96. data/lib/action_dispatch/middleware/session/cookie_store.rb +3 -9
  97. data/lib/action_dispatch/middleware/show_exceptions.rb +3 -2
  98. data/lib/action_dispatch/middleware/ssl.rb +20 -15
  99. data/lib/action_dispatch/middleware/stack.rb +56 -2
  100. data/lib/action_dispatch/middleware/static.rb +153 -93
  101. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  102. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  103. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  104. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +3 -1
  105. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  106. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
  107. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
  108. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
  109. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
  110. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +23 -4
  111. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
  112. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +6 -3
  113. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +4 -1
  114. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +104 -8
  115. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
  116. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  117. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
  118. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
  119. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +2 -2
  120. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
  121. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +24 -1
  122. data/lib/action_dispatch/railtie.rb +8 -2
  123. data/lib/action_dispatch/request/session.rb +11 -10
  124. data/lib/action_dispatch/request/utils.rb +26 -2
  125. data/lib/action_dispatch/routing/inspector.rb +100 -52
  126. data/lib/action_dispatch/routing/mapper.rb +155 -103
  127. data/lib/action_dispatch/routing/polymorphic_routes.rb +13 -15
  128. data/lib/action_dispatch/routing/redirection.rb +4 -4
  129. data/lib/action_dispatch/routing/route_set.rb +71 -69
  130. data/lib/action_dispatch/routing/url_for.rb +2 -2
  131. data/lib/action_dispatch/routing.rb +21 -20
  132. data/lib/action_dispatch/system_test_case.rb +54 -11
  133. data/lib/action_dispatch/system_testing/browser.rb +53 -16
  134. data/lib/action_dispatch/system_testing/driver.rb +11 -3
  135. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +49 -7
  136. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +8 -10
  137. data/lib/action_dispatch/testing/assertion_response.rb +0 -1
  138. data/lib/action_dispatch/testing/assertions/response.rb +4 -7
  139. data/lib/action_dispatch/testing/assertions/routing.rb +20 -8
  140. data/lib/action_dispatch/testing/assertions.rb +1 -1
  141. data/lib/action_dispatch/testing/integration.rb +60 -28
  142. data/lib/action_dispatch/testing/request_encoder.rb +2 -2
  143. data/lib/action_dispatch/testing/test_process.rb +29 -4
  144. data/lib/action_dispatch/testing/test_request.rb +3 -3
  145. data/lib/action_dispatch/testing/test_response.rb +4 -32
  146. data/lib/action_dispatch.rb +9 -3
  147. data/lib/action_pack/gem_version.rb +4 -4
  148. data/lib/action_pack.rb +1 -1
  149. metadata +35 -23
  150. data/lib/action_controller/metal/force_ssl.rb +0 -99
  151. data/lib/action_dispatch/http/parameter_filter.rb +0 -86
  152. data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
  153. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -49
  154. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -120
  155. 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
- Hash[params.map { |k, v| [k, Rack::Utils.escape(v)] }]
68
+ params.transform_values { |v| Rack::Utils.escape(v) }
69
69
  end
70
70
 
71
71
  def escape_fragment(params)
72
- Hash[params.map { |k, v| [k, Journey::Router::Utils.escape_fragment(v)] }]
72
+ params.transform_values { |v| Journey::Router::Utils.escape_fragment(v) }
73
73
  end
74
74
 
75
75
  def escape_path(params)
76
- Hash[params.map { |k, v| [k, Journey::Router::Utils.escape_path(v)] }]
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 +do end+ syntax for the redirect block wouldn't work, as Ruby would pass
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
- return [404, { "X-Cascade" => "pass" }, []]
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.send :remove_method, helper
91
+ @path_helpers_module.remove_method helper
95
92
  end
96
93
 
97
94
  @url_helpers.each do |helper|
98
- @url_helpers_module.send :remove_method, helper
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.send :undef_method, path_name
113
- @url_helpers_module.send :undef_method, url_name
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
- define_url_helper @path_helpers_module, route, path_name, route.defaults, name, PATH
117
- define_url_helper @url_helpers_module, route, url_name, route.defaults, name, UNKNOWN
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
- define_method(path_name) do |*args|
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
- define_method(url_name) do |*args|
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, url_strategy)
174
+ def self.create(route, options, route_name)
176
175
  if optimize_helper?(route)
177
- OptimizedUrlHelper.new(route, options, route_name, url_strategy)
176
+ OptimizedUrlHelper.new(route, options, route_name)
178
177
  else
179
- new route, options, route_name, url_strategy
178
+ new(route, options, route_name)
180
179
  end
181
180
  end
182
181
 
183
182
  def self.optimize_helper?(route)
184
- !route.glob? && route.path.requirements.empty?
183
+ route.path.requirements.empty? && !route.glob?
185
184
  end
186
185
 
187
- attr_reader :url_strategy, :route_name
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, url_strategy)
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}".dup
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, url_strategy)
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, route, name, opts, route_key, url_strategy)
320
- helper = UrlHelper.create(route, opts, route_key, url_strategy)
321
- mod.module_eval do
322
- define_method(name) do |*args|
323
- last = args.last
324
- options = \
325
- case last
326
- when Hash
327
- args.pop
328
- when ActionController::Parameters
329
- args.pop.to_h
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 urls to send to the client
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".freeze
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
- "http://guides.rubyonrails.org/routing.html#restricting-the-routes-created"
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 6.0.
600
+ will be removed in Rails 6.2.
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 6.0.
607
+ will be removed in Rails 6.2.
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?("/".freeze)
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 [path, params].
742
- # If no route is generated the formatter will raise ActionController::UrlGenerationError
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, PARAMETERIZE)
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
- route_key = options.delete :use_route
770
- path, params = generate(route_key, options, recall)
771
- return path, params.keys
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(route_key, options, recall = {})
775
- Generator.new(route_key, options, recall, self).generate
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
- RESERVED_OPTIONS.each { |ro| path_options.delete ro }
820
+ reserved.each { |ro| path_options.delete ro }
821
821
 
822
- path, params = generate(route_name, path_options, recall)
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 path =~ %r{://}
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.parser.unescape(value)
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' => 'posts#show'
78
- # post 'post/:id' => 'posts#create_comment'
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' => 'posts#show', via: [:get, :post]
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' => 'accounts#login', as: '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' => :list
124
- # get 'blog/delete' => :delete
125
- # get 'blog/edit' => :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' => 'articles#find_by_id', constraints: {
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' => :show, constraints: {
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' => :show, constraints: {
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' => :show, constraints: {
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" => redirect("/posts")
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 "こんにちは" => "welcome#index"
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" => Sprockets
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
- # opts = {controller: "plugin", action: "checkout", id: "2"}
214
- # assert_routing "plugin/checkout/2", opts
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
- # opts = {controller: "plugin", action: "show", id: "12"}
223
- # assert_recognizes opts, "/plugins/show/12"
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 controllers by prefixing the command with <tt>-c</tt> option.
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", ">= 2.15"
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 'application_system_test_case'
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,36 @@ 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 < IntegrationTest
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
- include SystemTesting::TestHelpers::UndefMethods
101
117
 
102
118
  def initialize(*) # :nodoc:
103
119
  super
120
+ self.class.driven_by(:selenium) unless self.class.driver?
104
121
  self.class.driver.use
105
122
  end
106
123
 
@@ -134,14 +151,40 @@ module ActionDispatch
134
151
  # driven_by :selenium, using: :firefox
135
152
  #
136
153
  # driven_by :selenium, using: :headless_firefox
137
- def self.driven_by(driver, using: :chrome, screen_size: [1400, 1400], options: {})
138
- self.driver = SystemTesting::Driver.new(driver, using: using, screen_size: screen_size, options: options)
154
+ def self.driven_by(driver, using: :chrome, screen_size: [1400, 1400], options: {}, &capabilities)
155
+ driver_options = { using: using, screen_size: screen_size, options: options }
156
+
157
+ self.driver = SystemTesting::Driver.new(driver, **driver_options, &capabilities)
139
158
  end
140
159
 
141
- driven_by :selenium
160
+ private
161
+ def url_helpers
162
+ @url_helpers ||=
163
+ if ActionDispatch.test_app
164
+ Class.new do
165
+ include ActionDispatch.test_app.routes.url_helpers
166
+ include ActionDispatch.test_app.routes.mounted_helpers
142
167
 
143
- ActiveSupport.run_load_hooks(:action_dispatch_system_test_case, self)
144
- end
168
+ def url_options
169
+ default_url_options.reverse_merge(host: Capybara.app_host || Capybara.current_session.server_url)
170
+ end
171
+ end.new
172
+ end
173
+ end
174
+
175
+ def method_missing(name, *args, &block)
176
+ if url_helpers.respond_to?(name)
177
+ url_helpers.public_send(name, *args, &block)
178
+ else
179
+ super
180
+ end
181
+ end
145
182
 
146
- SystemTestCase.start_application
183
+ def respond_to_missing?(name, include_private = false)
184
+ url_helpers.respond_to?(name)
185
+ end
186
+ end
147
187
  end
188
+
189
+ ActiveSupport.run_load_hooks :action_dispatch_system_test_case, ActionDispatch::SystemTestCase
190
+ ActionDispatch::SystemTestCase.start_application