actionpack 5.2.4.rc1 → 6.0.0.rc2

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 (127) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +179 -335
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +3 -2
  5. data/lib/abstract_controller/base.rb +4 -2
  6. data/lib/abstract_controller/caching/fragments.rb +6 -22
  7. data/lib/abstract_controller/callbacks.rb +12 -0
  8. data/lib/abstract_controller/collector.rb +1 -1
  9. data/lib/abstract_controller/helpers.rb +2 -2
  10. data/lib/abstract_controller/railties/routes_helpers.rb +1 -1
  11. data/lib/abstract_controller/translation.rb +1 -0
  12. data/lib/action_controller.rb +1 -0
  13. data/lib/action_controller/api.rb +2 -1
  14. data/lib/action_controller/base.rb +2 -7
  15. data/lib/action_controller/caching.rb +1 -1
  16. data/lib/action_controller/log_subscriber.rb +8 -5
  17. data/lib/action_controller/metal.rb +1 -1
  18. data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
  19. data/lib/action_controller/metal/conditional_get.rb +9 -3
  20. data/lib/action_controller/metal/data_streaming.rb +5 -6
  21. data/lib/action_controller/metal/default_headers.rb +17 -0
  22. data/lib/action_controller/metal/etag_with_template_digest.rb +1 -1
  23. data/lib/action_controller/metal/exceptions.rb +22 -1
  24. data/lib/action_controller/metal/flash.rb +5 -5
  25. data/lib/action_controller/metal/force_ssl.rb +15 -56
  26. data/lib/action_controller/metal/head.rb +1 -1
  27. data/lib/action_controller/metal/helpers.rb +3 -4
  28. data/lib/action_controller/metal/http_authentication.rb +20 -21
  29. data/lib/action_controller/metal/implicit_render.rb +4 -14
  30. data/lib/action_controller/metal/instrumentation.rb +3 -5
  31. data/lib/action_controller/metal/live.rb +29 -27
  32. data/lib/action_controller/metal/mime_responds.rb +13 -2
  33. data/lib/action_controller/metal/params_wrapper.rb +17 -13
  34. data/lib/action_controller/metal/redirecting.rb +5 -5
  35. data/lib/action_controller/metal/renderers.rb +1 -1
  36. data/lib/action_controller/metal/rendering.rb +2 -2
  37. data/lib/action_controller/metal/request_forgery_protection.rb +23 -12
  38. data/lib/action_controller/metal/strong_parameters.rb +63 -44
  39. data/lib/action_controller/metal/url_for.rb +1 -1
  40. data/lib/action_controller/railties/helpers.rb +1 -1
  41. data/lib/action_controller/renderer.rb +16 -3
  42. data/lib/action_controller/template_assertions.rb +1 -1
  43. data/lib/action_controller/test_case.rb +3 -7
  44. data/lib/action_dispatch.rb +4 -1
  45. data/lib/action_dispatch/http/cache.rb +14 -10
  46. data/lib/action_dispatch/http/content_disposition.rb +45 -0
  47. data/lib/action_dispatch/http/content_security_policy.rb +28 -16
  48. data/lib/action_dispatch/http/filter_parameters.rb +8 -6
  49. data/lib/action_dispatch/http/filter_redirect.rb +1 -1
  50. data/lib/action_dispatch/http/headers.rb +1 -1
  51. data/lib/action_dispatch/http/mime_negotiation.rb +7 -5
  52. data/lib/action_dispatch/http/mime_type.rb +14 -6
  53. data/lib/action_dispatch/http/parameter_filter.rb +5 -79
  54. data/lib/action_dispatch/http/parameters.rb +13 -3
  55. data/lib/action_dispatch/http/request.rb +10 -13
  56. data/lib/action_dispatch/http/response.rb +33 -19
  57. data/lib/action_dispatch/http/upload.rb +9 -1
  58. data/lib/action_dispatch/http/url.rb +81 -81
  59. data/lib/action_dispatch/journey/formatter.rb +2 -2
  60. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -2
  61. data/lib/action_dispatch/journey/nodes/node.rb +9 -8
  62. data/lib/action_dispatch/journey/path/pattern.rb +6 -2
  63. data/lib/action_dispatch/journey/route.rb +5 -4
  64. data/lib/action_dispatch/journey/router.rb +0 -3
  65. data/lib/action_dispatch/journey/router/utils.rb +10 -10
  66. data/lib/action_dispatch/journey/routes.rb +0 -1
  67. data/lib/action_dispatch/journey/scanner.rb +11 -4
  68. data/lib/action_dispatch/journey/visitors.rb +1 -1
  69. data/lib/action_dispatch/middleware/actionable_exceptions.rb +39 -0
  70. data/lib/action_dispatch/middleware/callbacks.rb +2 -4
  71. data/lib/action_dispatch/middleware/cookies.rb +46 -72
  72. data/lib/action_dispatch/middleware/debug_exceptions.rb +39 -59
  73. data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
  74. data/lib/action_dispatch/middleware/debug_view.rb +68 -0
  75. data/lib/action_dispatch/middleware/exception_wrapper.rb +49 -15
  76. data/lib/action_dispatch/middleware/flash.rb +1 -1
  77. data/lib/action_dispatch/middleware/host_authorization.rb +103 -0
  78. data/lib/action_dispatch/middleware/public_exceptions.rb +6 -2
  79. data/lib/action_dispatch/middleware/remote_ip.rb +6 -8
  80. data/lib/action_dispatch/middleware/request_id.rb +2 -2
  81. data/lib/action_dispatch/middleware/session/cookie_store.rb +1 -6
  82. data/lib/action_dispatch/middleware/show_exceptions.rb +1 -1
  83. data/lib/action_dispatch/middleware/ssl.rb +8 -8
  84. data/lib/action_dispatch/middleware/stack.rb +33 -1
  85. data/lib/action_dispatch/middleware/static.rb +5 -6
  86. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  87. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  88. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +3 -1
  89. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  90. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
  91. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
  92. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
  93. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
  94. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +26 -4
  95. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
  96. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +7 -4
  97. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +4 -2
  98. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +4 -0
  99. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
  100. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  101. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
  102. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
  103. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +2 -2
  104. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +3 -0
  105. data/lib/action_dispatch/railtie.rb +3 -0
  106. data/lib/action_dispatch/request/session.rb +8 -0
  107. data/lib/action_dispatch/routing.rb +21 -20
  108. data/lib/action_dispatch/routing/inspector.rb +99 -50
  109. data/lib/action_dispatch/routing/mapper.rb +60 -38
  110. data/lib/action_dispatch/routing/polymorphic_routes.rb +3 -4
  111. data/lib/action_dispatch/routing/route_set.rb +24 -27
  112. data/lib/action_dispatch/routing/url_for.rb +1 -0
  113. data/lib/action_dispatch/system_test_case.rb +23 -2
  114. data/lib/action_dispatch/system_testing/browser.rb +38 -7
  115. data/lib/action_dispatch/system_testing/driver.rb +10 -1
  116. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +6 -5
  117. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +7 -5
  118. data/lib/action_dispatch/testing/assertions.rb +1 -1
  119. data/lib/action_dispatch/testing/assertions/response.rb +2 -3
  120. data/lib/action_dispatch/testing/assertions/routing.rb +15 -3
  121. data/lib/action_dispatch/testing/integration.rb +12 -5
  122. data/lib/action_dispatch/testing/request_encoder.rb +2 -2
  123. data/lib/action_dispatch/testing/test_process.rb +2 -2
  124. data/lib/action_dispatch/testing/test_response.rb +4 -32
  125. data/lib/action_pack.rb +1 -1
  126. data/lib/action_pack/gem_version.rb +4 -4
  127. metadata +24 -13
@@ -50,7 +50,19 @@ module ActionDispatch
50
50
 
51
51
  private
52
52
  def constraint_args(constraint, request)
53
- constraint.arity == 1 ? [request] : [request.path_parameters, request]
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
- attr_reader :to, :default_controller, :default_action
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
- route = Journey::Route.new(name,
152
- application,
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 =~ ANCHOR_CHARACTERS_REGEX
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.".dup
312
- message << " See http://guides.rubyonrails.org/routing.html#specifying-a-controller-to-use"
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 controller =~ %r{\A/}
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 Whitelist
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: Whitelist.new, via: :get
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, <<-MSG.strip_heredoc unless path
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? name
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] = "".freeze
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.delete(:shallow)
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 action =~ /^[\w\-\/]+$/
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
- name = has_named_route?(name_for_action(:root, nil)) ? nil : :root
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
@@ -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. It uses
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".freeze][nil]; end
186
- def self.path; CACHE["path".freeze][nil]; end
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
- return [404, { "X-Cascade" => "pass" }, []]
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.send :remove_method, helper
93
+ @path_helpers_module.remove_method helper
95
94
  end
96
95
 
97
96
  @url_helpers.each do |helper|
98
- @url_helpers_module.send :remove_method, helper
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.send :undef_method, path_name
113
- @url_helpers_module.send :undef_method, url_name
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
- 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
@@ -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}".dup
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.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
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 urls to send to the client
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".freeze
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
- "http://guides.rubyonrails.org/routing.html#restricting-the-routes-created"
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.0.
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.0.
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?("/".freeze)
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,6 +4,7 @@ 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"
@@ -89,6 +90,24 @@ module ActionDispatch
89
90
  # { js_errors: true }
90
91
  # end
91
92
  #
93
+ # Some drivers require browser capabilities to be passed as a block instead
94
+ # of through the +options+ hash.
95
+ #
96
+ # As an example, if you want to add mobile emulation on chrome, you'll have to
97
+ # create an instance of selenium's +Chrome::Options+ object and add
98
+ # capabilities with a block.
99
+ #
100
+ # The block will be passed an instance of <tt><Driver>::Options</tt> where you can
101
+ # define the capabilities you want. Please refer to your driver documentation
102
+ # to learn about supported options.
103
+ #
104
+ # class ApplicationSystemTestCase < ActionDispatch::SystemTestCase
105
+ # driven_by :selenium, using: :chrome, screen_size: [1024, 768] do |driver_option|
106
+ # driver_option.add_emulation(device_name: 'iPhone 6')
107
+ # driver_option.add_extension('path/to/chrome_extension.crx')
108
+ # end
109
+ # end
110
+ #
92
111
  # Because <tt>ActionDispatch::SystemTestCase</tt> is a shim between Capybara
93
112
  # and Rails, any driver that is supported by Capybara is supported by system
94
113
  # tests as long as you include the required gems and files.
@@ -134,8 +153,10 @@ 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
- self.driver = SystemTesting::Driver.new(driver, using: using, screen_size: screen_size, options: options)
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
  driven_by :selenium