actionpack 5.2.1 → 7.0.2.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 (167) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +264 -220
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -6
  5. data/lib/abstract_controller/asset_paths.rb +1 -1
  6. data/lib/abstract_controller/base.rb +24 -4
  7. data/lib/abstract_controller/caching/fragments.rb +8 -24
  8. data/lib/abstract_controller/caching.rb +2 -2
  9. data/lib/abstract_controller/callbacks.rb +34 -8
  10. data/lib/abstract_controller/collector.rb +5 -4
  11. data/lib/abstract_controller/error.rb +1 -1
  12. data/lib/abstract_controller/helpers.rb +107 -90
  13. data/lib/abstract_controller/logger.rb +1 -1
  14. data/lib/abstract_controller/railties/routes_helpers.rb +19 -1
  15. data/lib/abstract_controller/rendering.rb +9 -9
  16. data/lib/abstract_controller/translation.rb +12 -5
  17. data/lib/abstract_controller/url_for.rb +4 -6
  18. data/lib/abstract_controller.rb +2 -0
  19. data/lib/action_controller/api.rb +5 -4
  20. data/lib/action_controller/base.rb +6 -9
  21. data/lib/action_controller/caching.rb +1 -3
  22. data/lib/action_controller/log_subscriber.rb +13 -9
  23. data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
  24. data/lib/action_controller/metal/conditional_get.rb +57 -6
  25. data/lib/action_controller/metal/content_security_policy.rb +2 -3
  26. data/lib/action_controller/metal/cookies.rb +4 -2
  27. data/lib/action_controller/metal/data_streaming.rb +9 -18
  28. data/lib/action_controller/metal/default_headers.rb +17 -0
  29. data/lib/action_controller/metal/etag_with_template_digest.rb +4 -6
  30. data/lib/action_controller/metal/exceptions.rb +55 -12
  31. data/lib/action_controller/metal/flash.rb +10 -6
  32. data/lib/action_controller/metal/head.rb +7 -4
  33. data/lib/action_controller/metal/helpers.rb +15 -6
  34. data/lib/action_controller/metal/http_authentication.rb +41 -39
  35. data/lib/action_controller/metal/implicit_render.rb +5 -15
  36. data/lib/action_controller/metal/instrumentation.rb +59 -55
  37. data/lib/action_controller/metal/live.rb +80 -33
  38. data/lib/action_controller/metal/logging.rb +20 -0
  39. data/lib/action_controller/metal/mime_responds.rb +22 -7
  40. data/lib/action_controller/metal/parameter_encoding.rb +35 -4
  41. data/lib/action_controller/metal/params_wrapper.rb +50 -31
  42. data/lib/action_controller/metal/permissions_policy.rb +46 -0
  43. data/lib/action_controller/metal/redirecting.rb +93 -23
  44. data/lib/action_controller/metal/renderers.rb +4 -4
  45. data/lib/action_controller/metal/rendering.rb +14 -9
  46. data/lib/action_controller/metal/request_forgery_protection.rb +160 -58
  47. data/lib/action_controller/metal/rescue.rb +2 -2
  48. data/lib/action_controller/metal/streaming.rb +1 -4
  49. data/lib/action_controller/metal/strong_parameters.rb +236 -88
  50. data/lib/action_controller/metal/testing.rb +9 -2
  51. data/lib/action_controller/metal/url_for.rb +1 -1
  52. data/lib/action_controller/metal.rb +16 -17
  53. data/lib/action_controller/railtie.rb +49 -6
  54. data/lib/action_controller/railties/helpers.rb +1 -1
  55. data/lib/action_controller/renderer.rb +37 -13
  56. data/lib/action_controller/template_assertions.rb +1 -1
  57. data/lib/action_controller/test_case.rb +98 -68
  58. data/lib/action_controller.rb +4 -5
  59. data/lib/action_dispatch/http/cache.rb +45 -32
  60. data/lib/action_dispatch/http/content_disposition.rb +45 -0
  61. data/lib/action_dispatch/http/content_security_policy.rb +69 -56
  62. data/lib/action_dispatch/http/filter_parameters.rb +14 -8
  63. data/lib/action_dispatch/http/filter_redirect.rb +2 -3
  64. data/lib/action_dispatch/http/headers.rb +4 -4
  65. data/lib/action_dispatch/http/mime_negotiation.rb +44 -16
  66. data/lib/action_dispatch/http/mime_type.rb +47 -30
  67. data/lib/action_dispatch/http/parameters.rb +18 -27
  68. data/lib/action_dispatch/http/permissions_policy.rb +173 -0
  69. data/lib/action_dispatch/http/request.rb +49 -35
  70. data/lib/action_dispatch/http/response.rb +34 -26
  71. data/lib/action_dispatch/http/upload.rb +9 -1
  72. data/lib/action_dispatch/http/url.rb +86 -94
  73. data/lib/action_dispatch/journey/formatter.rb +55 -31
  74. data/lib/action_dispatch/journey/gtg/builder.rb +30 -46
  75. data/lib/action_dispatch/journey/gtg/simulator.rb +15 -8
  76. data/lib/action_dispatch/journey/gtg/transition_table.rb +78 -21
  77. data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
  78. data/lib/action_dispatch/journey/nodes/node.rb +83 -16
  79. data/lib/action_dispatch/journey/parser.rb +13 -13
  80. data/lib/action_dispatch/journey/parser.y +1 -1
  81. data/lib/action_dispatch/journey/path/pattern.rb +42 -34
  82. data/lib/action_dispatch/journey/route.rb +14 -31
  83. data/lib/action_dispatch/journey/router/utils.rb +16 -14
  84. data/lib/action_dispatch/journey/router.rb +27 -35
  85. data/lib/action_dispatch/journey/routes.rb +3 -5
  86. data/lib/action_dispatch/journey/scanner.rb +10 -4
  87. data/lib/action_dispatch/journey/visitors.rb +1 -4
  88. data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
  89. data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
  90. data/lib/action_dispatch/journey.rb +0 -2
  91. data/lib/action_dispatch/middleware/actionable_exceptions.rb +45 -0
  92. data/lib/action_dispatch/middleware/callbacks.rb +2 -4
  93. data/lib/action_dispatch/middleware/cookies.rb +136 -113
  94. data/lib/action_dispatch/middleware/debug_exceptions.rb +47 -68
  95. data/lib/action_dispatch/middleware/debug_locks.rb +8 -8
  96. data/lib/action_dispatch/middleware/debug_view.rb +66 -0
  97. data/lib/action_dispatch/middleware/exception_wrapper.rb +79 -30
  98. data/lib/action_dispatch/middleware/executor.rb +4 -1
  99. data/lib/action_dispatch/middleware/flash.rb +10 -12
  100. data/lib/action_dispatch/middleware/host_authorization.rb +159 -0
  101. data/lib/action_dispatch/middleware/public_exceptions.rb +6 -3
  102. data/lib/action_dispatch/middleware/remote_ip.rb +30 -20
  103. data/lib/action_dispatch/middleware/request_id.rb +5 -6
  104. data/lib/action_dispatch/middleware/server_timing.rb +33 -0
  105. data/lib/action_dispatch/middleware/session/abstract_store.rb +16 -3
  106. data/lib/action_dispatch/middleware/session/cache_store.rb +11 -6
  107. data/lib/action_dispatch/middleware/session/cookie_store.rb +24 -19
  108. data/lib/action_dispatch/middleware/show_exceptions.rb +20 -11
  109. data/lib/action_dispatch/middleware/ssl.rb +20 -15
  110. data/lib/action_dispatch/middleware/stack.rb +79 -7
  111. data/lib/action_dispatch/middleware/static.rb +150 -94
  112. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  113. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  114. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  115. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +6 -11
  116. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  117. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
  118. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +46 -36
  119. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +8 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +7 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +25 -6
  122. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
  123. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +9 -6
  124. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +4 -1
  125. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +121 -15
  126. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
  127. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  128. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +5 -5
  129. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +4 -4
  130. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +5 -5
  131. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +4 -4
  132. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +16 -2
  133. data/lib/action_dispatch/railtie.rb +16 -4
  134. data/lib/action_dispatch/request/session.rb +59 -22
  135. data/lib/action_dispatch/request/utils.rb +28 -2
  136. data/lib/action_dispatch/routing/inspector.rb +102 -54
  137. data/lib/action_dispatch/routing/mapper.rb +184 -156
  138. data/lib/action_dispatch/routing/polymorphic_routes.rb +21 -19
  139. data/lib/action_dispatch/routing/redirection.rb +4 -6
  140. data/lib/action_dispatch/routing/route_set.rb +83 -73
  141. data/lib/action_dispatch/routing/routes_proxy.rb +1 -1
  142. data/lib/action_dispatch/routing/url_for.rb +2 -3
  143. data/lib/action_dispatch/routing.rb +23 -22
  144. data/lib/action_dispatch/system_test_case.rb +65 -16
  145. data/lib/action_dispatch/system_testing/browser.rb +43 -16
  146. data/lib/action_dispatch/system_testing/driver.rb +42 -10
  147. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +58 -12
  148. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +3 -10
  149. data/lib/action_dispatch/testing/assertion_response.rb +0 -1
  150. data/lib/action_dispatch/testing/assertions/response.rb +4 -7
  151. data/lib/action_dispatch/testing/assertions/routing.rb +20 -8
  152. data/lib/action_dispatch/testing/assertions.rb +3 -6
  153. data/lib/action_dispatch/testing/integration.rb +61 -30
  154. data/lib/action_dispatch/testing/request_encoder.rb +2 -2
  155. data/lib/action_dispatch/testing/test_process.rb +8 -6
  156. data/lib/action_dispatch/testing/test_request.rb +3 -3
  157. data/lib/action_dispatch/testing/test_response.rb +4 -32
  158. data/lib/action_dispatch.rb +15 -7
  159. data/lib/action_pack/gem_version.rb +4 -4
  160. data/lib/action_pack.rb +1 -1
  161. metadata +44 -25
  162. data/lib/action_controller/metal/force_ssl.rb +0 -99
  163. data/lib/action_dispatch/http/parameter_filter.rb +0 -86
  164. data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
  165. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -49
  166. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -120
  167. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
@@ -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)
@@ -146,6 +145,7 @@ module ActionDispatch
146
145
 
147
146
  %w(edit new).each do |action|
148
147
  module_eval <<-EOT, __FILE__, __LINE__ + 1
148
+ # frozen_string_literal: true
149
149
  def #{action}_polymorphic_url(record_or_hash, options = {})
150
150
  polymorphic_url_for_action("#{action}", record_or_hash, options)
151
151
  end
@@ -157,7 +157,6 @@ module ActionDispatch
157
157
  end
158
158
 
159
159
  private
160
-
161
160
  def polymorphic_url_for_action(action, record_or_hash, options)
162
161
  polymorphic_url(record_or_hash, options.merge(action: action))
163
162
  end
@@ -175,15 +174,15 @@ module ActionDispatch
175
174
  end
176
175
 
177
176
  class HelperMethodBuilder # :nodoc:
178
- CACHE = { "path" => {}, "url" => {} }
177
+ CACHE = { path: {}, url: {} }
179
178
 
180
179
  def self.get(action, type)
181
- type = type.to_s
180
+ type = type.to_sym
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}_" : ""
@@ -229,9 +228,9 @@ module ActionDispatch
229
228
  end
230
229
 
231
230
  if options.empty?
232
- recipient.send(method, *args)
231
+ recipient.public_send(method, *args)
233
232
  else
234
- recipient.send(method, *args, options)
233
+ recipient.public_send(method, *args, options)
235
234
  end
236
235
  end
237
236
 
@@ -248,7 +247,7 @@ module ActionDispatch
248
247
  end
249
248
 
250
249
  def handle_string_call(target, str)
251
- target.send get_method_for_string str
250
+ target.public_send get_method_for_string str
252
251
  end
253
252
 
254
253
  def handle_class(klass)
@@ -256,7 +255,7 @@ module ActionDispatch
256
255
  end
257
256
 
258
257
  def handle_class_call(target, klass)
259
- target.send get_method_for_class klass
258
+ target.public_send get_method_for_class klass
260
259
  end
261
260
 
262
261
  def handle_model(record)
@@ -278,7 +277,7 @@ module ActionDispatch
278
277
  mapping.call(target, [record], suffix == "path")
279
278
  else
280
279
  method, args = handle_model(record)
281
- target.send(method, *args)
280
+ target.public_send(method, *args)
282
281
  end
283
282
  end
284
283
 
@@ -288,10 +287,12 @@ module ActionDispatch
288
287
 
289
288
  args = []
290
289
 
291
- route = record_list.map { |parent|
290
+ route = record_list.map do |parent|
292
291
  case parent
293
- when Symbol, String
292
+ when Symbol
294
293
  parent.to_s
294
+ when String
295
+ raise(ArgumentError, "Please use symbols for polymorphic route arguments.")
295
296
  when Class
296
297
  args << parent
297
298
  parent.model_name.singular_route_key
@@ -299,12 +300,14 @@ module ActionDispatch
299
300
  args << parent.to_model
300
301
  parent.to_model.model_name.singular_route_key
301
302
  end
302
- }
303
+ end
303
304
 
304
305
  route <<
305
306
  case record
306
- when Symbol, String
307
+ when Symbol
307
308
  record.to_s
309
+ when String
310
+ raise(ArgumentError, "Please use symbols for polymorphic route arguments.")
308
311
  when Class
309
312
  @key_strategy.call record.model_name
310
313
  else
@@ -324,7 +327,6 @@ module ActionDispatch
324
327
  end
325
328
 
326
329
  private
327
-
328
330
  def polymorphic_mapping(target, record)
329
331
  if record.respond_to?(:to_model)
330
332
  target._routes.polymorphic_mappings[record.to_model.model_name.name]
@@ -343,8 +345,8 @@ module ActionDispatch
343
345
  end
344
346
 
345
347
  [nil, "new", "edit"].each do |action|
346
- CACHE["url"][action] = build action, "url"
347
- CACHE["path"][action] = build action, "path"
348
+ CACHE[:url][action] = build action, "url"
349
+ CACHE[:path][action] = build action, "path"
348
350
  end
349
351
  end
350
352
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "action_dispatch/http/request"
4
- require "active_support/core_ext/uri"
5
3
  require "active_support/core_ext/array/extract_options"
6
4
  require "rack/utils"
7
5
  require "action_controller/metal/exceptions"
@@ -65,15 +63,15 @@ module ActionDispatch
65
63
  end
66
64
 
67
65
  def escape(params)
68
- Hash[params.map { |k, v| [k, Rack::Utils.escape(v)] }]
66
+ params.transform_values { |v| Rack::Utils.escape(v) }
69
67
  end
70
68
 
71
69
  def escape_fragment(params)
72
- Hash[params.map { |k, v| [k, Journey::Router::Utils.escape_fragment(v)] }]
70
+ params.transform_values { |v| Journey::Router::Utils.escape_fragment(v) }
73
71
  end
74
72
 
75
73
  def escape_path(params)
76
- Hash[params.map { |k, v| [k, Journey::Router::Utils.escape_path(v)] }]
74
+ params.transform_values { |v| Journey::Router::Utils.escape_path(v) }
77
75
  end
78
76
  end
79
77
 
@@ -164,7 +162,7 @@ module ActionDispatch
164
162
  # "http://#{request.host_with_port}/#{path}"
165
163
  # }
166
164
  #
167
- # Note that the +do end+ syntax for the redirect block wouldn't work, as Ruby would pass
165
+ # Note that the <tt>do end</tt> syntax for the redirect block wouldn't work, as Ruby would pass
168
166
  # the block to +get+ instead of +redirect+. Use <tt>{ ... }</tt> instead.
169
167
  #
170
168
  # The options version of redirect allows you to supply only the parts of the URL which need
@@ -2,12 +2,10 @@
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"
9
8
  require "action_controller/metal/exceptions"
10
- require "action_dispatch/http/request"
11
9
  require "action_dispatch/routing/endpoint"
12
10
 
13
11
  module ActionDispatch
@@ -36,12 +34,11 @@ module ActionDispatch
36
34
  if @raise_on_name_error
37
35
  raise
38
36
  else
39
- return [404, { "X-Cascade" => "pass" }, []]
37
+ [404, { "X-Cascade" => "pass" }, []]
40
38
  end
41
39
  end
42
40
 
43
41
  private
44
-
45
42
  def controller(req)
46
43
  req.controller_class
47
44
  rescue NameError => e
@@ -60,7 +57,6 @@ module ActionDispatch
60
57
  end
61
58
 
62
59
  private
63
-
64
60
  def controller(_); @controller_class; end
65
61
  end
66
62
 
@@ -91,11 +87,11 @@ module ActionDispatch
91
87
 
92
88
  def clear!
93
89
  @path_helpers.each do |helper|
94
- @path_helpers_module.send :remove_method, helper
90
+ @path_helpers_module.remove_method helper
95
91
  end
96
92
 
97
93
  @url_helpers.each do |helper|
98
- @url_helpers_module.send :remove_method, helper
94
+ @url_helpers_module.remove_method helper
99
95
  end
100
96
 
101
97
  @routes.clear
@@ -109,12 +105,14 @@ module ActionDispatch
109
105
  url_name = :"#{name}_url"
110
106
 
111
107
  if routes.key? key
112
- @path_helpers_module.send :undef_method, path_name
113
- @url_helpers_module.send :undef_method, url_name
108
+ @path_helpers_module.undef_method path_name
109
+ @url_helpers_module.undef_method url_name
114
110
  end
115
111
  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
112
+
113
+ helper = UrlHelper.create(route, route.defaults, name)
114
+ define_url_helper @path_helpers_module, path_name, helper, PATH
115
+ define_url_helper @url_helpers_module, url_name, helper, UNKNOWN
118
116
 
119
117
  @path_helpers << path_name
120
118
  @url_helpers << url_name
@@ -133,8 +131,8 @@ module ActionDispatch
133
131
  alias [] get
134
132
  alias clear clear!
135
133
 
136
- def each
137
- routes.each { |name, route| yield name, route }
134
+ def each(&block)
135
+ routes.each(&block)
138
136
  self
139
137
  end
140
138
 
@@ -154,13 +152,13 @@ module ActionDispatch
154
152
  url_name = :"#{name}_url"
155
153
 
156
154
  @path_helpers_module.module_eval do
157
- define_method(path_name) do |*args|
155
+ redefine_method(path_name) do |*args|
158
156
  helper.call(self, args, true)
159
157
  end
160
158
  end
161
159
 
162
160
  @url_helpers_module.module_eval do
163
- define_method(url_name) do |*args|
161
+ redefine_method(url_name) do |*args|
164
162
  helper.call(self, args, false)
165
163
  end
166
164
  end
@@ -172,30 +170,30 @@ module ActionDispatch
172
170
  end
173
171
 
174
172
  class UrlHelper
175
- def self.create(route, options, route_name, url_strategy)
173
+ def self.create(route, options, route_name)
176
174
  if optimize_helper?(route)
177
- OptimizedUrlHelper.new(route, options, route_name, url_strategy)
175
+ OptimizedUrlHelper.new(route, options, route_name)
178
176
  else
179
- new route, options, route_name, url_strategy
177
+ new(route, options, route_name)
180
178
  end
181
179
  end
182
180
 
183
181
  def self.optimize_helper?(route)
184
- !route.glob? && route.path.requirements.empty?
182
+ route.path.requirements.empty? && !route.glob?
185
183
  end
186
184
 
187
- attr_reader :url_strategy, :route_name
185
+ attr_reader :route_name
188
186
 
189
187
  class OptimizedUrlHelper < UrlHelper
190
188
  attr_reader :arg_size
191
189
 
192
- def initialize(route, options, route_name, url_strategy)
190
+ def initialize(route, options, route_name)
193
191
  super
194
192
  @required_parts = @route.required_parts
195
193
  @arg_size = @required_parts.size
196
194
  end
197
195
 
198
- def call(t, args, inner_options)
196
+ def call(t, method_name, args, inner_options, url_strategy)
199
197
  if args.size == arg_size && !inner_options && optimize_routes_generation?(t)
200
198
  options = t.url_options.merge @options
201
199
  options[:path] = optimized_helper(args)
@@ -216,7 +214,6 @@ module ActionDispatch
216
214
  end
217
215
 
218
216
  private
219
-
220
217
  def optimized_helper(args)
221
218
  params = parameterize_args(args) do
222
219
  raise_generation_error(args)
@@ -246,22 +243,21 @@ module ActionDispatch
246
243
  missing_keys << missing_key
247
244
  }
248
245
  constraints = Hash[@route.requirements.merge(params).sort_by { |k, v| k.to_s }]
249
- message = "No route matches #{constraints.inspect}".dup
246
+ message = +"No route matches #{constraints.inspect}"
250
247
  message << ", missing required keys: #{missing_keys.sort.inspect}"
251
248
 
252
249
  raise ActionController::UrlGenerationError, message
253
250
  end
254
251
  end
255
252
 
256
- def initialize(route, options, route_name, url_strategy)
253
+ def initialize(route, options, route_name)
257
254
  @options = options
258
255
  @segment_keys = route.segment_keys.uniq
259
256
  @route = route
260
- @url_strategy = url_strategy
261
257
  @route_name = route_name
262
258
  end
263
259
 
264
- def call(t, args, inner_options)
260
+ def call(t, method_name, args, inner_options, url_strategy)
265
261
  controller_options = t.url_options
266
262
  options = controller_options.merge @options
267
263
  hash = handle_positional_args(controller_options,
@@ -270,7 +266,7 @@ module ActionDispatch
270
266
  options,
271
267
  @segment_keys)
272
268
 
273
- t._routes.url_for(hash, route_name, url_strategy)
269
+ t._routes.url_for(hash, route_name, url_strategy, method_name)
274
270
  end
275
271
 
276
272
  def handle_positional_args(controller_options, inner_options, args, result, path_params)
@@ -316,31 +312,28 @@ module ActionDispatch
316
312
  #
317
313
  # foo_url(bar, baz, bang, sort_by: 'baz')
318
314
  #
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
315
+ def define_url_helper(mod, name, helper, url_strategy)
316
+ mod.define_method(name) do |*args|
317
+ last = args.last
318
+ options = \
319
+ case last
320
+ when Hash
321
+ args.pop
322
+ when ActionController::Parameters
323
+ args.pop.to_h
324
+ end
325
+ helper.call(self, name, args, options, url_strategy)
333
326
  end
334
327
  end
335
328
  end
336
329
 
337
- # strategy for building urls to send to the client
330
+ # strategy for building URLs to send to the client
338
331
  PATH = ->(options) { ActionDispatch::Http::URL.path_for(options) }
339
332
  UNKNOWN = ->(options) { ActionDispatch::Http::URL.url_for(options) }
340
333
 
341
334
  attr_accessor :formatter, :set, :named_routes, :default_scope, :router
342
335
  attr_accessor :disable_clear_and_finalize, :resources_path_names
343
- attr_accessor :default_url_options
336
+ attr_accessor :default_url_options, :draw_paths
344
337
  attr_reader :env_key, :polymorphic_mappings
345
338
 
346
339
  alias :routes :set
@@ -372,13 +365,14 @@ module ActionDispatch
372
365
  self.named_routes = NamedRouteCollection.new
373
366
  self.resources_path_names = self.class.default_resources_path_names
374
367
  self.default_url_options = {}
368
+ self.draw_paths = []
375
369
 
376
370
  @config = config
377
371
  @append = []
378
372
  @prepend = []
379
373
  @disable_clear_and_finalize = false
380
374
  @finalized = false
381
- @env_key = "ROUTES_#{object_id}_SCRIPT_NAME".freeze
375
+ @env_key = "ROUTES_#{object_id}_SCRIPT_NAME"
382
376
 
383
377
  @set = Journey::Routes.new
384
378
  @router = Journey::Router.new @set
@@ -482,6 +476,14 @@ module ActionDispatch
482
476
  end
483
477
 
484
478
  def url_helpers(supports_path = true)
479
+ if supports_path
480
+ @url_helpers_with_paths ||= generate_url_helpers(true)
481
+ else
482
+ @url_helpers_without_paths ||= generate_url_helpers(false)
483
+ end
484
+ end
485
+
486
+ def generate_url_helpers(supports_path)
485
487
  routes = self
486
488
 
487
489
  Module.new do
@@ -585,7 +587,7 @@ module ActionDispatch
585
587
  "You may have defined two routes with the same name using the `:as` option, or " \
586
588
  "you may be overriding a route already defined by a resource with the same naming. " \
587
589
  "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"
590
+ "https://guides.rubyonrails.org/routing.html#restricting-the-routes-created"
589
591
  end
590
592
 
591
593
  route = @set.add_route(name, mapping)
@@ -594,14 +596,14 @@ module ActionDispatch
594
596
  if route.segment_keys.include?(:controller)
595
597
  ActiveSupport::Deprecation.warn(<<-MSG.squish)
596
598
  Using a dynamic :controller segment in a route is deprecated and
597
- will be removed in Rails 6.0.
599
+ will be removed in Rails 7.1.
598
600
  MSG
599
601
  end
600
602
 
601
603
  if route.segment_keys.include?(:action)
602
604
  ActiveSupport::Deprecation.warn(<<-MSG.squish)
603
605
  Using a dynamic :action segment in a route is deprecated and
604
- will be removed in Rails 6.0.
606
+ will be removed in Rails 7.1.
605
607
  MSG
606
608
  end
607
609
 
@@ -647,14 +649,6 @@ module ActionDispatch
647
649
  end
648
650
 
649
651
  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
652
  attr_reader :options, :recall, :set, :named_route
659
653
 
660
654
  def initialize(named_route, options, recall, set)
@@ -730,7 +724,7 @@ module ActionDispatch
730
724
  # Remove leading slashes from controllers
731
725
  def normalize_controller!
732
726
  if controller
733
- if controller.start_with?("/".freeze)
727
+ if controller.start_with?("/")
734
728
  @options[:controller] = controller[1..-1]
735
729
  else
736
730
  @options[:controller] = controller
@@ -738,10 +732,10 @@ module ActionDispatch
738
732
  end
739
733
  end
740
734
 
741
- # Generates a path from routes, returns [path, params].
742
- # If no route is generated the formatter will raise ActionController::UrlGenerationError
735
+ # Generates a path from routes, returns a RouteWithParams or MissingRoute.
736
+ # MissingRoute will raise ActionController::UrlGenerationError.
743
737
  def generate
744
- @set.formatter.generate(named_route, options, recall, PARAMETERIZE)
738
+ @set.formatter.generate(named_route, options, recall)
745
739
  end
746
740
 
747
741
  def different_controller?
@@ -766,13 +760,18 @@ module ActionDispatch
766
760
  end
767
761
 
768
762
  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
763
+ if recall
764
+ options = options.merge(_recall: recall)
765
+ end
766
+
767
+ route_name = options.delete :use_route
768
+ generator = generate(route_name, options, recall)
769
+ path_info = path_for(options, route_name, [])
770
+ [URI(path_info).path, generator.params.except(:_recall).keys]
772
771
  end
773
772
 
774
- def generate(route_key, options, recall = {})
775
- Generator.new(route_key, options, recall, self).generate
773
+ def generate(route_name, options, recall = {}, method_name = nil)
774
+ Generator.new(route_name, options, recall, self).generate
776
775
  end
777
776
  private :generate
778
777
 
@@ -792,12 +791,12 @@ module ActionDispatch
792
791
  options.delete(:relative_url_root) || relative_url_root
793
792
  end
794
793
 
795
- def path_for(options, route_name = nil)
796
- url_for(options, route_name, PATH)
794
+ def path_for(options, route_name = nil, reserved = RESERVED_OPTIONS)
795
+ url_for(options, route_name, PATH, nil, reserved)
797
796
  end
798
797
 
799
798
  # The +options+ argument must be a hash whose keys are *symbols*.
800
- def url_for(options, route_name = nil, url_strategy = UNKNOWN)
799
+ def url_for(options, route_name = nil, url_strategy = UNKNOWN, method_name = nil, reserved = RESERVED_OPTIONS)
801
800
  options = default_url_options.merge options
802
801
 
803
802
  user = password = nil
@@ -817,12 +816,23 @@ module ActionDispatch
817
816
  end
818
817
 
819
818
  path_options = options.dup
820
- RESERVED_OPTIONS.each { |ro| path_options.delete ro }
819
+ reserved.each { |ro| path_options.delete ro }
821
820
 
822
- path, params = generate(route_name, path_options, recall)
821
+ route_with_params = generate(route_name, path_options, recall)
822
+ path = route_with_params.path(method_name)
823
+
824
+ if options[:trailing_slash] && !options[:format] && !path.end_with?("/")
825
+ path += "/"
826
+ end
827
+
828
+ params = route_with_params.params
823
829
 
824
830
  if options.key? :params
825
- params.merge! options[:params]
831
+ if options[:params]&.respond_to?(:to_hash)
832
+ params.merge! options[:params]
833
+ else
834
+ params[:params] = options[:params]
835
+ end
826
836
  end
827
837
 
828
838
  options[:path] = path
@@ -842,7 +852,7 @@ module ActionDispatch
842
852
 
843
853
  def recognize_path(path, environment = {})
844
854
  method = (environment[:method] || "GET").to_s.upcase
845
- path = Journey::Router::Utils.normalize_path(path) unless path =~ %r{://}
855
+ path = Journey::Router::Utils.normalize_path(path) unless %r{://}.match?(path)
846
856
  extras = environment[:extras] || {}
847
857
 
848
858
  begin
@@ -861,7 +871,7 @@ module ActionDispatch
861
871
  params.each do |key, value|
862
872
  if value.is_a?(String)
863
873
  value = value.dup.force_encoding(Encoding::BINARY)
864
- params[key] = URI.parser.unescape(value)
874
+ params[key] = URI::DEFAULT_PARSER.unescape(value)
865
875
  end
866
876
  end
867
877
  req.path_parameters = params
@@ -4,7 +4,7 @@ require "active_support/core_ext/array/extract_options"
4
4
 
5
5
  module ActionDispatch
6
6
  module Routing
7
- class RoutesProxy #:nodoc:
7
+ class RoutesProxy # :nodoc:
8
8
  include ActionDispatch::Routing::UrlFor
9
9
 
10
10
  attr_accessor :scope, :routes
@@ -103,7 +103,7 @@ module ActionDispatch
103
103
  include(*_url_for_modules) if respond_to?(:_url_for_modules)
104
104
  end
105
105
 
106
- def initialize(*)
106
+ def initialize(...)
107
107
  @_routes = nil
108
108
  super
109
109
  end
@@ -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
  #
@@ -214,13 +215,11 @@ module ActionDispatch
214
215
  end
215
216
 
216
217
  protected
217
-
218
218
  def optimize_routes_generation?
219
219
  _routes.optimize_routes_generation? && default_url_options.empty?
220
220
  end
221
221
 
222
222
  private
223
-
224
223
  def _with_routes(routes) # :doc:
225
224
  old_routes, @_routes = @_routes, routes
226
225
  yield