actionpack 7.0.8.1 → 7.2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +94 -500
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -2
  5. data/lib/abstract_controller/asset_paths.rb +2 -0
  6. data/lib/abstract_controller/base.rb +119 -106
  7. data/lib/abstract_controller/caching/fragments.rb +51 -52
  8. data/lib/abstract_controller/caching.rb +2 -0
  9. data/lib/abstract_controller/callbacks.rb +94 -67
  10. data/lib/abstract_controller/collector.rb +6 -6
  11. data/lib/abstract_controller/deprecator.rb +9 -0
  12. data/lib/abstract_controller/error.rb +2 -0
  13. data/lib/abstract_controller/helpers.rb +121 -91
  14. data/lib/abstract_controller/logger.rb +2 -0
  15. data/lib/abstract_controller/railties/routes_helpers.rb +3 -16
  16. data/lib/abstract_controller/rendering.rb +14 -13
  17. data/lib/abstract_controller/translation.rb +12 -30
  18. data/lib/abstract_controller/url_for.rb +9 -5
  19. data/lib/abstract_controller.rb +8 -0
  20. data/lib/action_controller/api/api_rendering.rb +2 -0
  21. data/lib/action_controller/api.rb +78 -73
  22. data/lib/action_controller/base.rb +199 -141
  23. data/lib/action_controller/caching.rb +16 -11
  24. data/lib/action_controller/deprecator.rb +9 -0
  25. data/lib/action_controller/form_builder.rb +21 -16
  26. data/lib/action_controller/log_subscriber.rb +19 -5
  27. data/lib/action_controller/metal/allow_browser.rb +123 -0
  28. data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
  29. data/lib/action_controller/metal/conditional_get.rb +187 -174
  30. data/lib/action_controller/metal/content_security_policy.rb +26 -25
  31. data/lib/action_controller/metal/cookies.rb +4 -2
  32. data/lib/action_controller/metal/data_streaming.rb +65 -54
  33. data/lib/action_controller/metal/default_headers.rb +6 -2
  34. data/lib/action_controller/metal/etag_with_flash.rb +4 -0
  35. data/lib/action_controller/metal/etag_with_template_digest.rb +18 -14
  36. data/lib/action_controller/metal/exceptions.rb +19 -9
  37. data/lib/action_controller/metal/flash.rb +12 -10
  38. data/lib/action_controller/metal/head.rb +20 -16
  39. data/lib/action_controller/metal/helpers.rb +64 -67
  40. data/lib/action_controller/metal/http_authentication.rb +214 -200
  41. data/lib/action_controller/metal/implicit_render.rb +21 -17
  42. data/lib/action_controller/metal/instrumentation.rb +22 -12
  43. data/lib/action_controller/metal/live.rb +125 -92
  44. data/lib/action_controller/metal/logging.rb +6 -4
  45. data/lib/action_controller/metal/mime_responds.rb +151 -142
  46. data/lib/action_controller/metal/parameter_encoding.rb +34 -32
  47. data/lib/action_controller/metal/params_wrapper.rb +58 -58
  48. data/lib/action_controller/metal/permissions_policy.rb +14 -13
  49. data/lib/action_controller/metal/rate_limiting.rb +62 -0
  50. data/lib/action_controller/metal/redirecting.rb +110 -84
  51. data/lib/action_controller/metal/renderers.rb +50 -49
  52. data/lib/action_controller/metal/rendering.rb +103 -82
  53. data/lib/action_controller/metal/request_forgery_protection.rb +279 -161
  54. data/lib/action_controller/metal/rescue.rb +12 -8
  55. data/lib/action_controller/metal/streaming.rb +174 -132
  56. data/lib/action_controller/metal/strong_parameters.rb +598 -473
  57. data/lib/action_controller/metal/testing.rb +2 -0
  58. data/lib/action_controller/metal/url_for.rb +23 -14
  59. data/lib/action_controller/metal.rb +145 -61
  60. data/lib/action_controller/railtie.rb +25 -9
  61. data/lib/action_controller/railties/helpers.rb +2 -0
  62. data/lib/action_controller/renderer.rb +105 -66
  63. data/lib/action_controller/template_assertions.rb +4 -2
  64. data/lib/action_controller/test_case.rb +157 -128
  65. data/lib/action_controller.rb +17 -3
  66. data/lib/action_dispatch/constants.rb +34 -0
  67. data/lib/action_dispatch/deprecator.rb +9 -0
  68. data/lib/action_dispatch/http/cache.rb +28 -29
  69. data/lib/action_dispatch/http/content_disposition.rb +2 -0
  70. data/lib/action_dispatch/http/content_security_policy.rb +69 -49
  71. data/lib/action_dispatch/http/filter_parameters.rb +27 -12
  72. data/lib/action_dispatch/http/filter_redirect.rb +22 -1
  73. data/lib/action_dispatch/http/headers.rb +23 -21
  74. data/lib/action_dispatch/http/mime_negotiation.rb +37 -48
  75. data/lib/action_dispatch/http/mime_type.rb +60 -30
  76. data/lib/action_dispatch/http/mime_types.rb +5 -1
  77. data/lib/action_dispatch/http/parameters.rb +12 -10
  78. data/lib/action_dispatch/http/permissions_policy.rb +32 -34
  79. data/lib/action_dispatch/http/rack_cache.rb +4 -0
  80. data/lib/action_dispatch/http/request.rb +132 -79
  81. data/lib/action_dispatch/http/response.rb +136 -103
  82. data/lib/action_dispatch/http/upload.rb +19 -15
  83. data/lib/action_dispatch/http/url.rb +75 -73
  84. data/lib/action_dispatch/journey/formatter.rb +19 -6
  85. data/lib/action_dispatch/journey/gtg/builder.rb +4 -3
  86. data/lib/action_dispatch/journey/gtg/simulator.rb +2 -0
  87. data/lib/action_dispatch/journey/gtg/transition_table.rb +10 -8
  88. data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
  89. data/lib/action_dispatch/journey/nodes/node.rb +6 -5
  90. data/lib/action_dispatch/journey/parser.rb +4 -3
  91. data/lib/action_dispatch/journey/parser_extras.rb +2 -0
  92. data/lib/action_dispatch/journey/path/pattern.rb +18 -15
  93. data/lib/action_dispatch/journey/route.rb +12 -9
  94. data/lib/action_dispatch/journey/router/utils.rb +16 -15
  95. data/lib/action_dispatch/journey/router.rb +13 -10
  96. data/lib/action_dispatch/journey/routes.rb +6 -4
  97. data/lib/action_dispatch/journey/scanner.rb +4 -2
  98. data/lib/action_dispatch/journey/visitors.rb +2 -0
  99. data/lib/action_dispatch/journey.rb +2 -0
  100. data/lib/action_dispatch/log_subscriber.rb +25 -0
  101. data/lib/action_dispatch/middleware/actionable_exceptions.rb +7 -6
  102. data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
  103. data/lib/action_dispatch/middleware/callbacks.rb +4 -0
  104. data/lib/action_dispatch/middleware/cookies.rb +192 -194
  105. data/lib/action_dispatch/middleware/debug_exceptions.rb +36 -27
  106. data/lib/action_dispatch/middleware/debug_locks.rb +18 -13
  107. data/lib/action_dispatch/middleware/debug_view.rb +9 -2
  108. data/lib/action_dispatch/middleware/exception_wrapper.rb +181 -27
  109. data/lib/action_dispatch/middleware/executor.rb +9 -1
  110. data/lib/action_dispatch/middleware/flash.rb +65 -46
  111. data/lib/action_dispatch/middleware/host_authorization.rb +22 -17
  112. data/lib/action_dispatch/middleware/public_exceptions.rb +12 -8
  113. data/lib/action_dispatch/middleware/reloader.rb +9 -5
  114. data/lib/action_dispatch/middleware/remote_ip.rb +88 -83
  115. data/lib/action_dispatch/middleware/request_id.rb +15 -8
  116. data/lib/action_dispatch/middleware/server_timing.rb +8 -6
  117. data/lib/action_dispatch/middleware/session/abstract_store.rb +7 -0
  118. data/lib/action_dispatch/middleware/session/cache_store.rb +14 -7
  119. data/lib/action_dispatch/middleware/session/cookie_store.rb +32 -25
  120. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +9 -3
  121. data/lib/action_dispatch/middleware/show_exceptions.rb +42 -28
  122. data/lib/action_dispatch/middleware/ssl.rb +60 -45
  123. data/lib/action_dispatch/middleware/stack.rb +15 -9
  124. data/lib/action_dispatch/middleware/static.rb +40 -34
  125. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
  126. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +4 -4
  127. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
  128. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +7 -7
  129. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
  130. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +17 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +16 -12
  132. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -1
  133. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
  134. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +4 -4
  135. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
  136. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
  137. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +3 -0
  138. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +47 -38
  139. data/lib/action_dispatch/railtie.rb +12 -4
  140. data/lib/action_dispatch/request/session.rb +39 -27
  141. data/lib/action_dispatch/request/utils.rb +10 -3
  142. data/lib/action_dispatch/routing/endpoint.rb +2 -0
  143. data/lib/action_dispatch/routing/inspector.rb +59 -9
  144. data/lib/action_dispatch/routing/mapper.rb +686 -639
  145. data/lib/action_dispatch/routing/polymorphic_routes.rb +70 -61
  146. data/lib/action_dispatch/routing/redirection.rb +52 -38
  147. data/lib/action_dispatch/routing/route_set.rb +106 -62
  148. data/lib/action_dispatch/routing/routes_proxy.rb +16 -19
  149. data/lib/action_dispatch/routing/url_for.rb +131 -122
  150. data/lib/action_dispatch/routing.rb +152 -150
  151. data/lib/action_dispatch/system_test_case.rb +91 -81
  152. data/lib/action_dispatch/system_testing/browser.rb +27 -19
  153. data/lib/action_dispatch/system_testing/driver.rb +16 -22
  154. data/lib/action_dispatch/system_testing/server.rb +2 -0
  155. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +53 -31
  156. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
  157. data/lib/action_dispatch/testing/assertion_response.rb +9 -7
  158. data/lib/action_dispatch/testing/assertions/response.rb +36 -26
  159. data/lib/action_dispatch/testing/assertions/routing.rb +203 -95
  160. data/lib/action_dispatch/testing/assertions.rb +5 -1
  161. data/lib/action_dispatch/testing/integration.rb +240 -229
  162. data/lib/action_dispatch/testing/request_encoder.rb +6 -1
  163. data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
  164. data/lib/action_dispatch/testing/test_process.rb +14 -9
  165. data/lib/action_dispatch/testing/test_request.rb +4 -2
  166. data/lib/action_dispatch/testing/test_response.rb +34 -19
  167. data/lib/action_dispatch.rb +52 -21
  168. data/lib/action_pack/gem_version.rb +5 -3
  169. data/lib/action_pack/version.rb +3 -1
  170. data/lib/action_pack.rb +18 -17
  171. metadata +91 -32
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "active_support/core_ext/hash/slice"
4
6
  require "active_support/core_ext/enumerable"
5
7
  require "active_support/core_ext/array/extract_options"
@@ -10,8 +12,20 @@ require "action_dispatch/routing/endpoint"
10
12
  module ActionDispatch
11
13
  module Routing
12
14
  class Mapper
15
+ class BacktraceCleaner < ActiveSupport::BacktraceCleaner # :nodoc:
16
+ def initialize
17
+ super
18
+ remove_silencers!
19
+ add_core_silencer
20
+ add_stdlib_silencer
21
+ end
22
+ end
23
+
13
24
  URL_OPTIONS = [:protocol, :subdomain, :domain, :host, :port]
14
25
 
26
+ cattr_accessor :route_source_locations, instance_accessor: false, default: false
27
+ cattr_accessor :backtrace_cleaner, instance_accessor: false, default: BacktraceCleaner.new
28
+
15
29
  class Constraints < Routing::Endpoint # :nodoc:
16
30
  attr_reader :app, :constraints
17
31
 
@@ -19,10 +33,10 @@ module ActionDispatch
19
33
  CALL = ->(app, req) { app.call req.env }
20
34
 
21
35
  def initialize(app, constraints, strategy)
22
- # Unwrap Constraints objects. I don't actually think it's possible
23
- # to pass a Constraints object to this constructor, but there were
24
- # multiple places that kept testing children of this object. I
25
- # *think* they were just being defensive, but I have no idea.
36
+ # Unwrap Constraints objects. I don't actually think it's possible to pass a
37
+ # Constraints object to this constructor, but there were multiple places that
38
+ # kept testing children of this object. I **think** they were just being
39
+ # defensive, but I have no idea.
26
40
  if app.is_a?(self.class)
27
41
  constraints += app.constraints
28
42
  app = app.app
@@ -43,7 +57,7 @@ module ActionDispatch
43
57
  end
44
58
 
45
59
  def serve(req)
46
- return [ 404, { "X-Cascade" => "pass" }, [] ] unless matches?(req)
60
+ return [ 404, { Constants::X_CASCADE => "pass" }, [] ] unless matches?(req)
47
61
 
48
62
  @strategy.call @app, req
49
63
  end
@@ -170,7 +184,7 @@ module ActionDispatch
170
184
  Journey::Route.new(name: name, app: application, path: path, constraints: conditions,
171
185
  required_defaults: required_defaults, defaults: defaults,
172
186
  request_method_match: request_method, precedence: precedence,
173
- scope_options: scope_options, internal: @internal)
187
+ scope_options: scope_options, internal: @internal, source_location: route_source_location)
174
188
  end
175
189
 
176
190
  def application
@@ -207,16 +221,28 @@ module ActionDispatch
207
221
  # Add a default constraint for :controller path segments that matches namespaced
208
222
  # controllers with default routes like :controller/:action/:id(.:format), e.g:
209
223
  # GET /admin/products/show/1
210
- # => { controller: 'admin/products', action: 'show', id: '1' }
224
+ # # > { controller: 'admin/products', action: 'show', id: '1' }
211
225
  options[:controller] ||= /.+?/
212
226
  end
213
227
 
214
228
  if to.respond_to?(:action) || to.respond_to?(:call)
215
229
  options
216
230
  else
217
- to_endpoint = split_to to
218
- controller = to_endpoint[0] || default_controller
219
- action = to_endpoint[1] || default_action
231
+ if to.nil?
232
+ controller = default_controller
233
+ action = default_action
234
+ elsif to.is_a?(String)
235
+ if to.include?("#")
236
+ to_endpoint = to.split("#").map!(&:-@)
237
+ controller = to_endpoint[0]
238
+ action = to_endpoint[1]
239
+ else
240
+ controller = default_controller
241
+ action = to
242
+ end
243
+ else
244
+ raise ArgumentError, ":to must respond to `action` or `call`, or it must be a String that includes '#', or the controller should be implicit"
245
+ end
220
246
 
221
247
  controller = add_controller_module(controller, modyoule)
222
248
 
@@ -305,14 +331,6 @@ module ActionDispatch
305
331
  hash
306
332
  end
307
333
 
308
- def split_to(to)
309
- if /#/.match?(to)
310
- to.split("#").map!(&:-@)
311
- else
312
- []
313
- end
314
- end
315
-
316
334
  def add_controller_module(controller, modyoule)
317
335
  if modyoule && !controller.is_a?(Regexp)
318
336
  if controller&.start_with?("/")
@@ -356,24 +374,54 @@ module ActionDispatch
356
374
  def dispatcher(raise_on_name_error)
357
375
  Routing::RouteSet::Dispatcher.new raise_on_name_error
358
376
  end
377
+
378
+ if Thread.respond_to?(:each_caller_location)
379
+ def route_source_location
380
+ if Mapper.route_source_locations
381
+ action_dispatch_dir = File.expand_path("..", __dir__)
382
+ Thread.each_caller_location do |location|
383
+ next if location.path.start_with?(action_dispatch_dir)
384
+
385
+ cleaned_path = Mapper.backtrace_cleaner.clean_frame(location.path)
386
+ next if cleaned_path.nil?
387
+
388
+ return "#{cleaned_path}:#{location.lineno}"
389
+ end
390
+ nil
391
+ end
392
+ end
393
+ else
394
+ def route_source_location
395
+ if Mapper.route_source_locations
396
+ action_dispatch_dir = File.expand_path("..", __dir__)
397
+ caller_locations.each do |location|
398
+ next if location.path.start_with?(action_dispatch_dir)
399
+
400
+ cleaned_path = Mapper.backtrace_cleaner.clean_frame(location.path)
401
+ next if cleaned_path.nil?
402
+
403
+ return "#{cleaned_path}:#{location.lineno}"
404
+ end
405
+ nil
406
+ end
407
+ end
408
+ end
359
409
  end
360
410
 
361
- # Invokes Journey::Router::Utils.normalize_path, then ensures that
362
- # /(:locale) becomes (/:locale). Except for root cases, where the
363
- # former is the correct one.
411
+ # Invokes Journey::Router::Utils.normalize_path, then ensures that /(:locale)
412
+ # becomes (/:locale). Except for root cases, where the former is the correct
413
+ # one.
364
414
  def self.normalize_path(path)
365
415
  path = Journey::Router::Utils.normalize_path(path)
366
416
 
367
417
  # the path for a root URL at this point can be something like
368
418
  # "/(/:locale)(/:platform)/(:browser)", and we would want
369
- # "/(:locale)(/:platform)(/:browser)"
370
-
371
- # reverse "/(", "/((" etc to "(/", "((/" etc
419
+ # "/(:locale)(/:platform)(/:browser)" reverse "/(", "/((" etc to "(/", "((/" etc
372
420
  path.gsub!(%r{/(\(+)/?}, '\1/')
373
- # if a path is all optional segments, change the leading "(/" back to
374
- # "/(" so it evaluates to "/" when interpreted with no options.
375
- # Unless, however, at least one secondary segment consists of a static
376
- # part, ex. "(/:locale)(/pages/:page)"
421
+ # if a path is all optional segments, change the leading "(/" back to "/(" so it
422
+ # evaluates to "/" when interpreted with no options. Unless, however, at least
423
+ # one secondary segment consists of a static part, ex.
424
+ # "(/:locale)(/pages/:page)"
377
425
  path.sub!(%r{^(\(+)/}, '/\1') if %r{^(\(+[^)]+\))(\(+/:[^)]+\))*$}.match?(path)
378
426
  path
379
427
  end
@@ -385,206 +433,202 @@ module ActionDispatch
385
433
  module Base
386
434
  # Matches a URL pattern to one or more routes.
387
435
  #
388
- # You should not use the +match+ method in your router
389
- # without specifying an HTTP method.
436
+ # You should not use the `match` method in your router without specifying an
437
+ # HTTP method.
390
438
  #
391
439
  # If you want to expose your action to both GET and POST, use:
392
440
  #
393
- # # sets :controller, :action, and :id in params
394
- # match ':controller/:action/:id', via: [:get, :post]
441
+ # # sets :controller, :action, and :id in params
442
+ # match ':controller/:action/:id', via: [:get, :post]
395
443
  #
396
- # Note that +:controller+, +:action+, and +:id+ are interpreted as URL
397
- # query parameters and thus available through +params+ in an action.
444
+ # Note that `:controller`, `:action`, and `:id` are interpreted as URL query
445
+ # parameters and thus available through `params` in an action.
398
446
  #
399
- # If you want to expose your action to GET, use +get+ in the router:
447
+ # If you want to expose your action to GET, use `get` in the router:
400
448
  #
401
449
  # Instead of:
402
450
  #
403
- # match ":controller/:action/:id"
451
+ # match ":controller/:action/:id"
404
452
  #
405
453
  # Do:
406
454
  #
407
- # get ":controller/:action/:id"
455
+ # get ":controller/:action/:id"
408
456
  #
409
- # Two of these symbols are special, +:controller+ maps to the controller
410
- # and +:action+ to the controller's action. A pattern can also map
411
- # wildcard segments (globs) to params:
457
+ # Two of these symbols are special, `:controller` maps to the controller and
458
+ # `:action` to the controller's action. A pattern can also map wildcard segments
459
+ # (globs) to params:
412
460
  #
413
- # get 'songs/*category/:title', to: 'songs#show'
461
+ # get 'songs/*category/:title', to: 'songs#show'
414
462
  #
415
- # # 'songs/rock/classic/stairway-to-heaven' sets
416
- # # params[:category] = 'rock/classic'
417
- # # params[:title] = 'stairway-to-heaven'
463
+ # # 'songs/rock/classic/stairway-to-heaven' sets
464
+ # # params[:category] = 'rock/classic'
465
+ # # params[:title] = 'stairway-to-heaven'
418
466
  #
419
- # To match a wildcard parameter, it must have a name assigned to it.
420
- # Without a variable name to attach the glob parameter to, the route
421
- # can't be parsed.
467
+ # To match a wildcard parameter, it must have a name assigned to it. Without a
468
+ # variable name to attach the glob parameter to, the route can't be parsed.
422
469
  #
423
- # When a pattern points to an internal route, the route's +:action+ and
424
- # +:controller+ should be set in options or hash shorthand. Examples:
470
+ # When a pattern points to an internal route, the route's `:action` and
471
+ # `:controller` should be set in options or hash shorthand. Examples:
425
472
  #
426
- # match 'photos/:id' => 'photos#show', via: :get
427
- # match 'photos/:id', to: 'photos#show', via: :get
428
- # match 'photos/:id', controller: 'photos', action: 'show', via: :get
473
+ # match 'photos/:id' => 'photos#show', via: :get
474
+ # match 'photos/:id', to: 'photos#show', via: :get
475
+ # match 'photos/:id', controller: 'photos', action: 'show', via: :get
429
476
  #
430
- # A pattern can also point to a +Rack+ endpoint i.e. anything that
431
- # responds to +call+:
477
+ # A pattern can also point to a `Rack` endpoint i.e. anything that responds to
478
+ # `call`:
432
479
  #
433
- # match 'photos/:id', to: -> (hash) { [200, {}, ["Coming soon"]] }, via: :get
434
- # match 'photos/:id', to: PhotoRackApp, via: :get
435
- # # Yes, controller actions are just rack endpoints
436
- # match 'photos/:id', to: PhotosController.action(:show), via: :get
480
+ # match 'photos/:id', to: -> (hash) { [200, {}, ["Coming soon"]] }, via: :get
481
+ # match 'photos/:id', to: PhotoRackApp, via: :get
482
+ # # Yes, controller actions are just rack endpoints
483
+ # match 'photos/:id', to: PhotosController.action(:show), via: :get
437
484
  #
438
485
  # Because requesting various HTTP verbs with a single action has security
439
- # implications, you must either specify the actions in
440
- # the via options or use one of the HttpHelpers[rdoc-ref:HttpHelpers]
441
- # instead +match+
486
+ # implications, you must either specify the actions in the via options or use
487
+ # one of the [HttpHelpers](rdoc-ref:HttpHelpers) instead `match`
442
488
  #
443
- # === Options
489
+ # ### Options
444
490
  #
445
491
  # Any options not seen here are passed on as params with the URL.
446
492
  #
447
- # [:controller]
448
- # The route's controller.
493
+ # :controller
494
+ # : The route's controller.
449
495
  #
450
- # [:action]
451
- # The route's action.
496
+ # :action
497
+ # : The route's action.
452
498
  #
453
- # [:param]
454
- # Overrides the default resource identifier +:id+ (name of the
455
- # dynamic segment used to generate the routes).
456
- # You can access that segment from your controller using
457
- # <tt>params[<:param>]</tt>.
458
- # In your router:
499
+ # :param
500
+ # : Overrides the default resource identifier `:id` (name of the dynamic
501
+ # segment used to generate the routes). You can access that segment from
502
+ # your controller using `params[<:param>]`. In your router:
459
503
  #
460
- # resources :users, param: :name
504
+ # resources :users, param: :name
461
505
  #
462
- # The +users+ resource here will have the following routes generated for it:
506
+ # The `users` resource here will have the following routes generated for it:
463
507
  #
464
- # GET /users(.:format)
465
- # POST /users(.:format)
466
- # GET /users/new(.:format)
467
- # GET /users/:name/edit(.:format)
468
- # GET /users/:name(.:format)
469
- # PATCH/PUT /users/:name(.:format)
470
- # DELETE /users/:name(.:format)
508
+ # GET /users(.:format)
509
+ # POST /users(.:format)
510
+ # GET /users/new(.:format)
511
+ # GET /users/:name/edit(.:format)
512
+ # GET /users/:name(.:format)
513
+ # PATCH/PUT /users/:name(.:format)
514
+ # DELETE /users/:name(.:format)
471
515
  #
472
- # You can override <tt>ActiveRecord::Base#to_param</tt> of a related
473
- # model to construct a URL:
516
+ # You can override `ActiveRecord::Base#to_param` of a related model to
517
+ # construct a URL:
474
518
  #
475
- # class User < ActiveRecord::Base
476
- # def to_param
477
- # name
478
- # end
479
- # end
519
+ # class User < ActiveRecord::Base
520
+ # def to_param
521
+ # name
522
+ # end
523
+ # end
480
524
  #
481
- # user = User.find_by(name: 'Phusion')
482
- # user_path(user) # => "/users/Phusion"
525
+ # user = User.find_by(name: 'Phusion')
526
+ # user_path(user) # => "/users/Phusion"
483
527
  #
484
- # [:path]
485
- # The path prefix for the routes.
528
+ # :path
529
+ # : The path prefix for the routes.
486
530
  #
487
- # [:module]
488
- # The namespace for :controller.
531
+ # :module
532
+ # : The namespace for :controller.
489
533
  #
490
- # match 'path', to: 'c#a', module: 'sekret', controller: 'posts', via: :get
491
- # # => Sekret::PostsController
534
+ # match 'path', to: 'c#a', module: 'sekret', controller: 'posts', via: :get
535
+ # # => Sekret::PostsController
492
536
  #
493
- # See <tt>Scoping#namespace</tt> for its scope equivalent.
537
+ # See `Scoping#namespace` for its scope equivalent.
494
538
  #
495
- # [:as]
496
- # The name used to generate routing helpers.
539
+ # :as
540
+ # : The name used to generate routing helpers.
497
541
  #
498
- # [:via]
499
- # Allowed HTTP verb(s) for route.
542
+ # :via
543
+ # : Allowed HTTP verb(s) for route.
500
544
  #
501
- # match 'path', to: 'c#a', via: :get
502
- # match 'path', to: 'c#a', via: [:get, :post]
503
- # match 'path', to: 'c#a', via: :all
545
+ # match 'path', to: 'c#a', via: :get
546
+ # match 'path', to: 'c#a', via: [:get, :post]
547
+ # match 'path', to: 'c#a', via: :all
504
548
  #
505
- # [:to]
506
- # Points to a +Rack+ endpoint. Can be an object that responds to
507
- # +call+ or a string representing a controller's action.
549
+ # :to
550
+ # : Points to a `Rack` endpoint. Can be an object that responds to `call` or a
551
+ # string representing a controller's action.
508
552
  #
509
- # match 'path', to: 'controller#action', via: :get
510
- # match 'path', to: -> (env) { [200, {}, ["Success!"]] }, via: :get
511
- # match 'path', to: RackApp, via: :get
553
+ # match 'path', to: 'controller#action', via: :get
554
+ # match 'path', to: -> (env) { [200, {}, ["Success!"]] }, via: :get
555
+ # match 'path', to: RackApp, via: :get
512
556
  #
513
- # [:on]
514
- # Shorthand for wrapping routes in a specific RESTful context. Valid
515
- # values are +:member+, +:collection+, and +:new+. Only use within
516
- # <tt>resource(s)</tt> block. For example:
557
+ # :on
558
+ # : Shorthand for wrapping routes in a specific RESTful context. Valid values
559
+ # are `:member`, `:collection`, and `:new`. Only use within `resource(s)`
560
+ # block. For example:
517
561
  #
518
- # resource :bar do
519
- # match 'foo', to: 'c#a', on: :member, via: [:get, :post]
520
- # end
562
+ # resource :bar do
563
+ # match 'foo', to: 'c#a', on: :member, via: [:get, :post]
564
+ # end
521
565
  #
522
- # Is equivalent to:
566
+ # Is equivalent to:
523
567
  #
524
- # resource :bar do
525
- # member do
526
- # match 'foo', to: 'c#a', via: [:get, :post]
527
- # end
528
- # end
568
+ # resource :bar do
569
+ # member do
570
+ # match 'foo', to: 'c#a', via: [:get, :post]
571
+ # end
572
+ # end
529
573
  #
530
- # [:constraints]
531
- # Constrains parameters with a hash of regular expressions
532
- # or an object that responds to <tt>matches?</tt>. In addition, constraints
533
- # other than path can also be specified with any object
534
- # that responds to <tt>===</tt> (e.g. String, Array, Range, etc.).
574
+ # :constraints
575
+ # : Constrains parameters with a hash of regular expressions or an object that
576
+ # responds to `matches?`. In addition, constraints other than path can also
577
+ # be specified with any object that responds to `===` (e.g. String, Array,
578
+ # Range, etc.).
535
579
  #
536
- # match 'path/:id', constraints: { id: /[A-Z]\d{5}/ }, via: :get
580
+ # match 'path/:id', constraints: { id: /[A-Z]\d{5}/ }, via: :get
537
581
  #
538
- # match 'json_only', constraints: { format: 'json' }, via: :get
582
+ # match 'json_only', constraints: { format: 'json' }, via: :get
539
583
  #
540
- # class PermitList
541
- # def matches?(request) request.remote_ip == '1.2.3.4' end
542
- # end
543
- # match 'path', to: 'c#a', constraints: PermitList.new, via: :get
584
+ # class PermitList
585
+ # def matches?(request) request.remote_ip == '1.2.3.4' end
586
+ # end
587
+ # match 'path', to: 'c#a', constraints: PermitList.new, via: :get
544
588
  #
545
- # See <tt>Scoping#constraints</tt> for more examples with its scope
546
- # equivalent.
589
+ # See `Scoping#constraints` for more examples with its scope equivalent.
547
590
  #
548
- # [:defaults]
549
- # Sets defaults for parameters
591
+ # :defaults
592
+ # : Sets defaults for parameters
550
593
  #
551
- # # Sets params[:format] to 'jpg' by default
552
- # match 'path', to: 'c#a', defaults: { format: 'jpg' }, via: :get
594
+ # # Sets params[:format] to 'jpg' by default
595
+ # match 'path', to: 'c#a', defaults: { format: 'jpg' }, via: :get
553
596
  #
554
- # See <tt>Scoping#defaults</tt> for its scope equivalent.
597
+ # See `Scoping#defaults` for its scope equivalent.
555
598
  #
556
- # [:anchor]
557
- # Boolean to anchor a <tt>match</tt> pattern. Default is true. When set to
558
- # false, the pattern matches any request prefixed with the given path.
599
+ # :anchor
600
+ # : Boolean to anchor a `match` pattern. Default is true. When set to false,
601
+ # the pattern matches any request prefixed with the given path.
559
602
  #
560
- # # Matches any request starting with 'path'
561
- # match 'path', to: 'c#a', anchor: false, via: :get
603
+ # # Matches any request starting with 'path'
604
+ # match 'path', to: 'c#a', anchor: false, via: :get
605
+ #
606
+ # :format
607
+ # : Allows you to specify the default value for optional `format` segment or
608
+ # disable it by supplying `false`.
562
609
  #
563
- # [:format]
564
- # Allows you to specify the default value for optional +format+
565
- # segment or disable it by supplying +false+.
566
610
  def match(path, options = nil)
567
611
  end
568
612
 
569
613
  # Mount a Rack-based application to be used within the application.
570
614
  #
571
- # mount SomeRackApp, at: "some_route"
615
+ # mount SomeRackApp, at: "some_route"
572
616
  #
573
617
  # Alternatively:
574
618
  #
575
- # mount(SomeRackApp => "some_route")
619
+ # mount(SomeRackApp => "some_route")
576
620
  #
577
- # For options, see +match+, as +mount+ uses it internally.
621
+ # For options, see `match`, as `mount` uses it internally.
578
622
  #
579
- # All mounted applications come with routing helpers to access them.
580
- # These are named after the class specified, so for the above example
581
- # the helper is either +some_rack_app_path+ or +some_rack_app_url+.
582
- # To customize this helper's name, use the +:as+ option:
623
+ # All mounted applications come with routing helpers to access them. These are
624
+ # named after the class specified, so for the above example the helper is either
625
+ # `some_rack_app_path` or `some_rack_app_url`. To customize this helper's name,
626
+ # use the `:as` option:
583
627
  #
584
- # mount(SomeRackApp => "some_route", as: "exciting")
628
+ # mount(SomeRackApp => "some_route", as: "exciting")
585
629
  #
586
- # This will generate the +exciting_path+ and +exciting_url+ helpers
587
- # which can be used to navigate to this mounted app.
630
+ # This will generate the `exciting_path` and `exciting_url` helpers which can be
631
+ # used to navigate to this mounted app.
588
632
  def mount(app, options = nil)
589
633
  if options
590
634
  path = options.delete(:at)
@@ -652,13 +696,14 @@ module ActionDispatch
652
696
 
653
697
  script_namer = ->(options) do
654
698
  prefix_options = options.slice(*_route.segment_keys)
655
- prefix_options[:relative_url_root] = ""
699
+ prefix_options[:script_name] = "" if options[:original_script_name]
656
700
 
657
701
  if options[:_recall]
658
702
  prefix_options.reverse_merge!(options[:_recall].slice(*_route.segment_keys))
659
703
  end
660
704
 
661
- # We must actually delete prefix segment keys to avoid passing them to next url_for.
705
+ # We must actually delete prefix segment keys to avoid passing them to next
706
+ # url_for.
662
707
  _route.segment_keys.each { |k| options.delete(k) }
663
708
  _url_helpers.public_send("#{name}_path", prefix_options)
664
709
  end
@@ -669,7 +714,7 @@ module ActionDispatch
669
714
  def optimize_routes_generation?; false; end
670
715
 
671
716
  define_method :find_script_name do |options|
672
- if options.key? :script_name
717
+ if options.key?(:script_name) && options[:script_name].present?
673
718
  super(options)
674
719
  else
675
720
  script_namer.call(options)
@@ -680,50 +725,50 @@ module ActionDispatch
680
725
  end
681
726
 
682
727
  module HttpHelpers
683
- # Define a route that only recognizes HTTP GET.
684
- # For supported arguments, see match[rdoc-ref:Base#match]
728
+ # Define a route that only recognizes HTTP GET. For supported arguments, see
729
+ # [match](rdoc-ref:Base#match)
685
730
  #
686
- # get 'bacon', to: 'food#bacon'
731
+ # get 'bacon', to: 'food#bacon'
687
732
  def get(*args, &block)
688
733
  map_method(:get, args, &block)
689
734
  end
690
735
 
691
- # Define a route that only recognizes HTTP POST.
692
- # For supported arguments, see match[rdoc-ref:Base#match]
736
+ # Define a route that only recognizes HTTP POST. For supported arguments, see
737
+ # [match](rdoc-ref:Base#match)
693
738
  #
694
- # post 'bacon', to: 'food#bacon'
739
+ # post 'bacon', to: 'food#bacon'
695
740
  def post(*args, &block)
696
741
  map_method(:post, args, &block)
697
742
  end
698
743
 
699
- # Define a route that only recognizes HTTP PATCH.
700
- # For supported arguments, see match[rdoc-ref:Base#match]
744
+ # Define a route that only recognizes HTTP PATCH. For supported arguments, see
745
+ # [match](rdoc-ref:Base#match)
701
746
  #
702
- # patch 'bacon', to: 'food#bacon'
747
+ # patch 'bacon', to: 'food#bacon'
703
748
  def patch(*args, &block)
704
749
  map_method(:patch, args, &block)
705
750
  end
706
751
 
707
- # Define a route that only recognizes HTTP PUT.
708
- # For supported arguments, see match[rdoc-ref:Base#match]
752
+ # Define a route that only recognizes HTTP PUT. For supported arguments, see
753
+ # [match](rdoc-ref:Base#match)
709
754
  #
710
- # put 'bacon', to: 'food#bacon'
755
+ # put 'bacon', to: 'food#bacon'
711
756
  def put(*args, &block)
712
757
  map_method(:put, args, &block)
713
758
  end
714
759
 
715
- # Define a route that only recognizes HTTP DELETE.
716
- # For supported arguments, see match[rdoc-ref:Base#match]
760
+ # Define a route that only recognizes HTTP DELETE. For supported arguments, see
761
+ # [match](rdoc-ref:Base#match)
717
762
  #
718
- # delete 'broccoli', to: 'food#broccoli'
763
+ # delete 'broccoli', to: 'food#broccoli'
719
764
  def delete(*args, &block)
720
765
  map_method(:delete, args, &block)
721
766
  end
722
767
 
723
- # Define a route that only recognizes HTTP OPTIONS.
724
- # For supported arguments, see match[rdoc-ref:Base#match]
768
+ # Define a route that only recognizes HTTP OPTIONS. For supported arguments, see
769
+ # [match](rdoc-ref:Base#match)
725
770
  #
726
- # options 'carrots', to: 'food#carrots'
771
+ # options 'carrots', to: 'food#carrots'
727
772
  def options(*args, &block)
728
773
  map_method(:options, args, &block)
729
774
  end
@@ -737,91 +782,90 @@ module ActionDispatch
737
782
  end
738
783
  end
739
784
 
740
- # You may wish to organize groups of controllers under a namespace.
741
- # Most commonly, you might group a number of administrative controllers
742
- # under an +admin+ namespace. You would place these controllers under
743
- # the <tt>app/controllers/admin</tt> directory, and you can group them
744
- # together in your router:
785
+ # You may wish to organize groups of controllers under a namespace. Most
786
+ # commonly, you might group a number of administrative controllers under an
787
+ # `admin` namespace. You would place these controllers under the
788
+ # `app/controllers/admin` directory, and you can group them together in your
789
+ # router:
745
790
  #
746
- # namespace "admin" do
747
- # resources :posts, :comments
748
- # end
791
+ # namespace "admin" do
792
+ # resources :posts, :comments
793
+ # end
749
794
  #
750
795
  # This will create a number of routes for each of the posts and comments
751
- # controller. For <tt>Admin::PostsController</tt>, Rails will create:
796
+ # controller. For `Admin::PostsController`, Rails will create:
752
797
  #
753
- # GET /admin/posts
754
- # GET /admin/posts/new
755
- # POST /admin/posts
756
- # GET /admin/posts/1
757
- # GET /admin/posts/1/edit
758
- # PATCH/PUT /admin/posts/1
759
- # DELETE /admin/posts/1
798
+ # GET /admin/posts
799
+ # GET /admin/posts/new
800
+ # POST /admin/posts
801
+ # GET /admin/posts/1
802
+ # GET /admin/posts/1/edit
803
+ # PATCH/PUT /admin/posts/1
804
+ # DELETE /admin/posts/1
760
805
  #
761
806
  # If you want to route /posts (without the prefix /admin) to
762
- # <tt>Admin::PostsController</tt>, you could use
807
+ # `Admin::PostsController`, you could use
763
808
  #
764
- # scope module: "admin" do
765
- # resources :posts
766
- # end
809
+ # scope module: "admin" do
810
+ # resources :posts
811
+ # end
767
812
  #
768
813
  # or, for a single case
769
814
  #
770
- # resources :posts, module: "admin"
815
+ # resources :posts, module: "admin"
771
816
  #
772
- # If you want to route /admin/posts to +PostsController+
773
- # (without the <tt>Admin::</tt> module prefix), you could use
817
+ # If you want to route /admin/posts to `PostsController` (without the `Admin::`
818
+ # module prefix), you could use
774
819
  #
775
- # scope "/admin" do
776
- # resources :posts
777
- # end
820
+ # scope "/admin" do
821
+ # resources :posts
822
+ # end
778
823
  #
779
824
  # or, for a single case
780
825
  #
781
- # resources :posts, path: "/admin/posts"
826
+ # resources :posts, path: "/admin/posts"
782
827
  #
783
- # In each of these cases, the named routes remain the same as if you did
784
- # not use scope. In the last case, the following paths map to
785
- # +PostsController+:
828
+ # In each of these cases, the named routes remain the same as if you did not use
829
+ # scope. In the last case, the following paths map to `PostsController`:
786
830
  #
787
- # GET /admin/posts
788
- # GET /admin/posts/new
789
- # POST /admin/posts
790
- # GET /admin/posts/1
791
- # GET /admin/posts/1/edit
792
- # PATCH/PUT /admin/posts/1
793
- # DELETE /admin/posts/1
831
+ # GET /admin/posts
832
+ # GET /admin/posts/new
833
+ # POST /admin/posts
834
+ # GET /admin/posts/1
835
+ # GET /admin/posts/1/edit
836
+ # PATCH/PUT /admin/posts/1
837
+ # DELETE /admin/posts/1
794
838
  module Scoping
795
839
  # Scopes a set of routes to the given default options.
796
840
  #
797
841
  # Take the following route definition as an example:
798
842
  #
799
- # scope path: ":account_id", as: "account" do
800
- # resources :projects
801
- # end
843
+ # scope path: ":account_id", as: "account" do
844
+ # resources :projects
845
+ # end
802
846
  #
803
- # This generates helpers such as +account_projects_path+, just like +resources+ does.
804
- # The difference here being that the routes generated are like /:account_id/projects,
805
- # rather than /accounts/:account_id/projects.
847
+ # This generates helpers such as `account_projects_path`, just like `resources`
848
+ # does. The difference here being that the routes generated are like
849
+ # /:account_id/projects, rather than /accounts/:account_id/projects.
806
850
  #
807
- # === Options
851
+ # ### Options
808
852
  #
809
- # Takes same options as <tt>Base#match</tt> and <tt>Resources#resources</tt>.
853
+ # Takes same options as `Base#match` and `Resources#resources`.
810
854
  #
811
- # # route /posts (without the prefix /admin) to <tt>Admin::PostsController</tt>
812
- # scope module: "admin" do
813
- # resources :posts
814
- # end
855
+ # # route /posts (without the prefix /admin) to +Admin::PostsController+
856
+ # scope module: "admin" do
857
+ # resources :posts
858
+ # end
815
859
  #
816
- # # prefix the posts resource's requests with '/admin'
817
- # scope path: "/admin" do
818
- # resources :posts
819
- # end
860
+ # # prefix the posts resource's requests with '/admin'
861
+ # scope path: "/admin" do
862
+ # resources :posts
863
+ # end
820
864
  #
821
- # # prefix the routing helper name: +sekret_posts_path+ instead of +posts_path+
822
- # scope as: "sekret" do
823
- # resources :posts
824
- # end
865
+ # # prefix the routing helper name: +sekret_posts_path+ instead of +posts_path+
866
+ # scope as: "sekret" do
867
+ # resources :posts
868
+ # end
825
869
  def scope(*args)
826
870
  options = args.extract_options!.dup
827
871
  scope = {}
@@ -878,9 +922,9 @@ module ActionDispatch
878
922
 
879
923
  # Scopes routes to a specific controller
880
924
  #
881
- # controller "food" do
882
- # match "bacon", action: :bacon, via: :get
883
- # end
925
+ # controller "food" do
926
+ # match "bacon", action: :bacon, via: :get
927
+ # end
884
928
  def controller(controller)
885
929
  @scope = @scope.new(controller: controller)
886
930
  yield
@@ -890,42 +934,42 @@ module ActionDispatch
890
934
 
891
935
  # Scopes routes to a specific namespace. For example:
892
936
  #
893
- # namespace :admin do
894
- # resources :posts
895
- # end
937
+ # namespace :admin do
938
+ # resources :posts
939
+ # end
896
940
  #
897
941
  # This generates the following routes:
898
942
  #
899
- # admin_posts GET /admin/posts(.:format) admin/posts#index
900
- # admin_posts POST /admin/posts(.:format) admin/posts#create
901
- # new_admin_post GET /admin/posts/new(.:format) admin/posts#new
902
- # edit_admin_post GET /admin/posts/:id/edit(.:format) admin/posts#edit
903
- # admin_post GET /admin/posts/:id(.:format) admin/posts#show
904
- # admin_post PATCH/PUT /admin/posts/:id(.:format) admin/posts#update
905
- # admin_post DELETE /admin/posts/:id(.:format) admin/posts#destroy
943
+ # admin_posts GET /admin/posts(.:format) admin/posts#index
944
+ # admin_posts POST /admin/posts(.:format) admin/posts#create
945
+ # new_admin_post GET /admin/posts/new(.:format) admin/posts#new
946
+ # edit_admin_post GET /admin/posts/:id/edit(.:format) admin/posts#edit
947
+ # admin_post GET /admin/posts/:id(.:format) admin/posts#show
948
+ # admin_post PATCH/PUT /admin/posts/:id(.:format) admin/posts#update
949
+ # admin_post DELETE /admin/posts/:id(.:format) admin/posts#destroy
906
950
  #
907
- # === Options
951
+ # ### Options
908
952
  #
909
- # The +:path+, +:as+, +:module+, +:shallow_path+, and +:shallow_prefix+
910
- # options all default to the name of the namespace.
953
+ # The `:path`, `:as`, `:module`, `:shallow_path`, and `:shallow_prefix` options
954
+ # all default to the name of the namespace.
911
955
  #
912
- # For options, see <tt>Base#match</tt>. For +:shallow_path+ option, see
913
- # <tt>Resources#resources</tt>.
956
+ # For options, see `Base#match`. For `:shallow_path` option, see
957
+ # `Resources#resources`.
914
958
  #
915
- # # accessible through /sekret/posts rather than /admin/posts
916
- # namespace :admin, path: "sekret" do
917
- # resources :posts
918
- # end
959
+ # # accessible through /sekret/posts rather than /admin/posts
960
+ # namespace :admin, path: "sekret" do
961
+ # resources :posts
962
+ # end
919
963
  #
920
- # # maps to <tt>Sekret::PostsController</tt> rather than <tt>Admin::PostsController</tt>
921
- # namespace :admin, module: "sekret" do
922
- # resources :posts
923
- # end
964
+ # # maps to +Sekret::PostsController+ rather than +Admin::PostsController+
965
+ # namespace :admin, module: "sekret" do
966
+ # resources :posts
967
+ # end
924
968
  #
925
- # # generates +sekret_posts_path+ rather than +admin_posts_path+
926
- # namespace :admin, as: "sekret" do
927
- # resources :posts
928
- # end
969
+ # # generates +sekret_posts_path+ rather than +admin_posts_path+
970
+ # namespace :admin, as: "sekret" do
971
+ # resources :posts
972
+ # end
929
973
  def namespace(path, options = {}, &block)
930
974
  path = path.to_s
931
975
 
@@ -941,70 +985,75 @@ module ActionDispatch
941
985
  end
942
986
  end
943
987
 
944
- # === Parameter Restriction
945
- # Allows you to constrain the nested routes based on a set of rules.
946
- # For instance, in order to change the routes to allow for a dot character in the +id+ parameter:
988
+ # ### Parameter Restriction
989
+ # Allows you to constrain the nested routes based on a set of rules. For
990
+ # instance, in order to change the routes to allow for a dot character in the
991
+ # `id` parameter:
947
992
  #
948
- # constraints(id: /\d+\.\d+/) do
949
- # resources :posts
950
- # end
993
+ # constraints(id: /\d+\.\d+/) do
994
+ # resources :posts
995
+ # end
951
996
  #
952
- # Now routes such as +/posts/1+ will no longer be valid, but +/posts/1.1+ will be.
953
- # The +id+ parameter must match the constraint passed in for this example.
997
+ # Now routes such as `/posts/1` will no longer be valid, but `/posts/1.1` will
998
+ # be. The `id` parameter must match the constraint passed in for this example.
954
999
  #
955
1000
  # You may use this to also restrict other parameters:
956
1001
  #
957
- # resources :posts do
958
- # constraints(post_id: /\d+\.\d+/) do
959
- # resources :comments
1002
+ # resources :posts do
1003
+ # constraints(post_id: /\d+\.\d+/) do
1004
+ # resources :comments
1005
+ # end
960
1006
  # end
961
- # end
962
1007
  #
963
- # === Restricting based on IP
1008
+ # ### Restricting based on IP
964
1009
  #
965
1010
  # Routes can also be constrained to an IP or a certain range of IP addresses:
966
1011
  #
967
- # constraints(ip: /192\.168\.\d+\.\d+/) do
968
- # resources :posts
969
- # end
1012
+ # constraints(ip: /192\.168\.\d+\.\d+/) do
1013
+ # resources :posts
1014
+ # end
970
1015
  #
971
- # Any user connecting from the 192.168.* range will be able to see this resource,
972
- # where as any user connecting outside of this range will be told there is no such route.
1016
+ # Any user connecting from the 192.168.* range will be able to see this
1017
+ # resource, where as any user connecting outside of this range will be told
1018
+ # there is no such route.
973
1019
  #
974
- # === Dynamic request matching
1020
+ # ### Dynamic request matching
975
1021
  #
976
1022
  # Requests to routes can be constrained based on specific criteria:
977
1023
  #
978
- # constraints(-> (req) { /iPhone/.match?(req.env["HTTP_USER_AGENT"]) }) do
979
- # resources :iphones
980
- # end
1024
+ # constraints(-> (req) { /iPhone/.match?(req.env["HTTP_USER_AGENT"]) }) do
1025
+ # resources :iphones
1026
+ # end
981
1027
  #
982
- # You are able to move this logic out into a class if it is too complex for routes.
983
- # This class must have a +matches?+ method defined on it which either returns +true+
984
- # if the user should be given access to that route, or +false+ if the user should not.
1028
+ # You are able to move this logic out into a class if it is too complex for
1029
+ # routes. This class must have a `matches?` method defined on it which either
1030
+ # returns `true` if the user should be given access to that route, or `false` if
1031
+ # the user should not.
985
1032
  #
986
- # class Iphone
987
- # def self.matches?(request)
988
- # /iPhone/.match?(request.env["HTTP_USER_AGENT"])
989
- # end
990
- # end
1033
+ # class Iphone
1034
+ # def self.matches?(request)
1035
+ # /iPhone/.match?(request.env["HTTP_USER_AGENT"])
1036
+ # end
1037
+ # end
991
1038
  #
992
- # An expected place for this code would be +lib/constraints+.
1039
+ # An expected place for this code would be `lib/constraints`.
993
1040
  #
994
1041
  # This class is then used like this:
995
1042
  #
996
- # constraints(Iphone) do
997
- # resources :iphones
998
- # end
1043
+ # constraints(Iphone) do
1044
+ # resources :iphones
1045
+ # end
999
1046
  def constraints(constraints = {}, &block)
1000
1047
  scope(constraints: constraints, &block)
1001
1048
  end
1002
1049
 
1003
1050
  # Allows you to set default parameters for a route, such as this:
1004
- # defaults id: 'home' do
1005
- # match 'scoped_pages/(:id)', to: 'pages#show'
1006
- # end
1007
- # Using this, the +:id+ parameter here will default to 'home'.
1051
+ #
1052
+ # defaults id: 'home' do
1053
+ # match 'scoped_pages/(:id)', to: 'pages#show'
1054
+ # end
1055
+ #
1056
+ # Using this, the `:id` parameter here will default to 'home'.
1008
1057
  def defaults(defaults = {})
1009
1058
  @scope = @scope.new(defaults: merge_defaults_scope(@scope[:defaults], defaults))
1010
1059
  yield
@@ -1080,48 +1129,46 @@ module ActionDispatch
1080
1129
  end
1081
1130
  end
1082
1131
 
1083
- # Resource routing allows you to quickly declare all of the common routes
1084
- # for a given resourceful controller. Instead of declaring separate routes
1085
- # for your +index+, +show+, +new+, +edit+, +create+, +update+, and +destroy+
1086
- # actions, a resourceful route declares them in a single line of code:
1132
+ # Resource routing allows you to quickly declare all of the common routes for a
1133
+ # given resourceful controller. Instead of declaring separate routes for your
1134
+ # `index`, `show`, `new`, `edit`, `create`, `update`, and `destroy` actions, a
1135
+ # resourceful route declares them in a single line of code:
1087
1136
  #
1088
- # resources :photos
1137
+ # resources :photos
1089
1138
  #
1090
- # Sometimes, you have a resource that clients always look up without
1091
- # referencing an ID. A common example, /profile always shows the profile of
1092
- # the currently logged in user. In this case, you can use a singular resource
1093
- # to map /profile (rather than /profile/:id) to the show action.
1139
+ # Sometimes, you have a resource that clients always look up without referencing
1140
+ # an ID. A common example, /profile always shows the profile of the currently
1141
+ # logged in user. In this case, you can use a singular resource to map /profile
1142
+ # (rather than /profile/:id) to the show action.
1094
1143
  #
1095
- # resource :profile
1144
+ # resource :profile
1096
1145
  #
1097
- # It's common to have resources that are logically children of other
1098
- # resources:
1146
+ # It's common to have resources that are logically children of other resources:
1099
1147
  #
1100
- # resources :magazines do
1101
- # resources :ads
1102
- # end
1148
+ # resources :magazines do
1149
+ # resources :ads
1150
+ # end
1103
1151
  #
1104
1152
  # You may wish to organize groups of controllers under a namespace. Most
1105
- # commonly, you might group a number of administrative controllers under
1106
- # an +admin+ namespace. You would place these controllers under the
1107
- # <tt>app/controllers/admin</tt> directory, and you can group them together
1108
- # in your router:
1109
- #
1110
- # namespace "admin" do
1111
- # resources :posts, :comments
1112
- # end
1153
+ # commonly, you might group a number of administrative controllers under an
1154
+ # `admin` namespace. You would place these controllers under the
1155
+ # `app/controllers/admin` directory, and you can group them together in your
1156
+ # router:
1113
1157
  #
1114
- # By default the +:id+ parameter doesn't accept dots. If you need to
1115
- # use dots as part of the +:id+ parameter add a constraint which
1116
- # overrides this restriction, e.g:
1158
+ # namespace "admin" do
1159
+ # resources :posts, :comments
1160
+ # end
1117
1161
  #
1118
- # resources :articles, id: /[^\/]+/
1162
+ # By default the `:id` parameter doesn't accept dots. If you need to use dots as
1163
+ # part of the `:id` parameter add a constraint which overrides this restriction,
1164
+ # e.g:
1119
1165
  #
1120
- # This allows any character other than a slash as part of your +:id+.
1166
+ # resources :articles, id: /[^\/]+/
1121
1167
  #
1168
+ # This allows any character other than a slash as part of your `:id`.
1122
1169
  module Resources
1123
- # CANONICAL_ACTIONS holds all actions that does not need a prefix or
1124
- # a path appended since they fit properly in their scope level.
1170
+ # CANONICAL_ACTIONS holds all actions that does not need a prefix or a path
1171
+ # appended since they fit properly in their scope level.
1125
1172
  VALID_ON_OPTIONS = [:new, :collection, :member]
1126
1173
  RESOURCE_OPTIONS = [:as, :controller, :path, :only, :except, :param, :concerns]
1127
1174
  CANONICAL_ACTIONS = %w(index create new show update destroy)
@@ -1184,8 +1231,8 @@ module ActionDispatch
1184
1231
 
1185
1232
  alias :member_name :singular
1186
1233
 
1187
- # Checks for uncountable plurals, and appends "_index" if the plural
1188
- # and singular form are the same.
1234
+ # Checks for uncountable plurals, and appends "_index" if the plural and
1235
+ # singular form are the same.
1189
1236
  def collection_name
1190
1237
  singular == plural ? "#{plural}_index" : plural
1191
1238
  end
@@ -1258,37 +1305,35 @@ module ActionDispatch
1258
1305
  @scope[:path_names].merge!(options)
1259
1306
  end
1260
1307
 
1261
- # Sometimes, you have a resource that clients always look up without
1262
- # referencing an ID. A common example, /profile always shows the
1263
- # profile of the currently logged in user. In this case, you can use
1264
- # a singular resource to map /profile (rather than /profile/:id) to
1265
- # the show action:
1308
+ # Sometimes, you have a resource that clients always look up without referencing
1309
+ # an ID. A common example, /profile always shows the profile of the currently
1310
+ # logged in user. In this case, you can use a singular resource to map /profile
1311
+ # (rather than /profile/:id) to the show action:
1266
1312
  #
1267
- # resource :profile
1313
+ # resource :profile
1268
1314
  #
1269
- # This creates six different routes in your application, all mapping to
1270
- # the +Profiles+ controller (note that the controller is named after
1271
- # the plural):
1315
+ # This creates six different routes in your application, all mapping to the
1316
+ # `Profiles` controller (note that the controller is named after the plural):
1272
1317
  #
1273
- # GET /profile/new
1274
- # GET /profile
1275
- # GET /profile/edit
1276
- # PATCH/PUT /profile
1277
- # DELETE /profile
1278
- # POST /profile
1318
+ # GET /profile/new
1319
+ # GET /profile
1320
+ # GET /profile/edit
1321
+ # PATCH/PUT /profile
1322
+ # DELETE /profile
1323
+ # POST /profile
1279
1324
  #
1280
- # If you want instances of a model to work with this resource via
1281
- # record identification (e.g. in +form_with+ or +redirect_to+), you
1282
- # will need to call resolve[rdoc-ref:CustomUrls#resolve]:
1325
+ # If you want instances of a model to work with this resource via record
1326
+ # identification (e.g. in `form_with` or `redirect_to`), you will need to call
1327
+ # [resolve](rdoc-ref:CustomUrls#resolve):
1283
1328
  #
1284
- # resource :profile
1285
- # resolve('Profile') { [:profile] }
1329
+ # resource :profile
1330
+ # resolve('Profile') { [:profile] }
1286
1331
  #
1287
- # # Enables this to work with singular routes:
1288
- # form_with(model: @profile) {}
1332
+ # # Enables this to work with singular routes:
1333
+ # form_with(model: @profile) {}
1289
1334
  #
1290
- # === Options
1291
- # Takes same options as resources[rdoc-ref:#resources]
1335
+ # ### Options
1336
+ # Takes same options as [resources](rdoc-ref:#resources)
1292
1337
  def resource(*resources, &block)
1293
1338
  options = resources.extract_options!.dup
1294
1339
 
@@ -1318,143 +1363,147 @@ module ActionDispatch
1318
1363
  self
1319
1364
  end
1320
1365
 
1321
- # In Rails, a resourceful route provides a mapping between HTTP verbs
1322
- # and URLs and controller actions. By convention, each action also maps
1323
- # to particular CRUD operations in a database. A single entry in the
1324
- # routing file, such as
1366
+ # In Rails, a resourceful route provides a mapping between HTTP verbs and URLs
1367
+ # and controller actions. By convention, each action also maps to particular
1368
+ # CRUD operations in a database. A single entry in the routing file, such as
1325
1369
  #
1326
- # resources :photos
1370
+ # resources :photos
1327
1371
  #
1328
- # creates seven different routes in your application, all mapping to
1329
- # the +Photos+ controller:
1372
+ # creates seven different routes in your application, all mapping to the
1373
+ # `Photos` controller:
1330
1374
  #
1331
- # GET /photos
1332
- # GET /photos/new
1333
- # POST /photos
1334
- # GET /photos/:id
1335
- # GET /photos/:id/edit
1336
- # PATCH/PUT /photos/:id
1337
- # DELETE /photos/:id
1375
+ # GET /photos
1376
+ # GET /photos/new
1377
+ # POST /photos
1378
+ # GET /photos/:id
1379
+ # GET /photos/:id/edit
1380
+ # PATCH/PUT /photos/:id
1381
+ # DELETE /photos/:id
1338
1382
  #
1339
1383
  # Resources can also be nested infinitely by using this block syntax:
1340
1384
  #
1341
- # resources :photos do
1342
- # resources :comments
1343
- # end
1385
+ # resources :photos do
1386
+ # resources :comments
1387
+ # end
1344
1388
  #
1345
1389
  # This generates the following comments routes:
1346
1390
  #
1347
- # GET /photos/:photo_id/comments
1348
- # GET /photos/:photo_id/comments/new
1349
- # POST /photos/:photo_id/comments
1350
- # GET /photos/:photo_id/comments/:id
1351
- # GET /photos/:photo_id/comments/:id/edit
1352
- # PATCH/PUT /photos/:photo_id/comments/:id
1353
- # DELETE /photos/:photo_id/comments/:id
1391
+ # GET /photos/:photo_id/comments
1392
+ # GET /photos/:photo_id/comments/new
1393
+ # POST /photos/:photo_id/comments
1394
+ # GET /photos/:photo_id/comments/:id
1395
+ # GET /photos/:photo_id/comments/:id/edit
1396
+ # PATCH/PUT /photos/:photo_id/comments/:id
1397
+ # DELETE /photos/:photo_id/comments/:id
1354
1398
  #
1355
- # === Options
1356
- # Takes same options as match[rdoc-ref:Base#match] as well as:
1399
+ # ### Options
1400
+ # Takes same options as [match](rdoc-ref:Base#match) as well as:
1357
1401
  #
1358
- # [:path_names]
1359
- # Allows you to change the segment component of the +edit+ and +new+ actions.
1360
- # Actions not specified are not changed.
1402
+ # :path_names
1403
+ # : Allows you to change the segment component of the `edit` and `new`
1404
+ # actions. Actions not specified are not changed.
1361
1405
  #
1362
- # resources :posts, path_names: { new: "brand_new" }
1406
+ # resources :posts, path_names: { new: "brand_new" }
1363
1407
  #
1364
- # The above example will now change /posts/new to /posts/brand_new.
1408
+ # The above example will now change /posts/new to /posts/brand_new.
1365
1409
  #
1366
- # [:path]
1367
- # Allows you to change the path prefix for the resource.
1410
+ # :path
1411
+ # : Allows you to change the path prefix for the resource.
1368
1412
  #
1369
- # resources :posts, path: 'postings'
1413
+ # resources :posts, path: 'postings'
1370
1414
  #
1371
- # The resource and all segments will now route to /postings instead of /posts.
1415
+ # The resource and all segments will now route to /postings instead of
1416
+ # /posts.
1372
1417
  #
1373
- # [:only]
1374
- # Only generate routes for the given actions.
1418
+ # :only
1419
+ # : Only generate routes for the given actions.
1375
1420
  #
1376
- # resources :cows, only: :show
1377
- # resources :cows, only: [:show, :index]
1421
+ # resources :cows, only: :show
1422
+ # resources :cows, only: [:show, :index]
1378
1423
  #
1379
- # [:except]
1380
- # Generate all routes except for the given actions.
1424
+ # :except
1425
+ # : Generate all routes except for the given actions.
1381
1426
  #
1382
- # resources :cows, except: :show
1383
- # resources :cows, except: [:show, :index]
1427
+ # resources :cows, except: :show
1428
+ # resources :cows, except: [:show, :index]
1384
1429
  #
1385
- # [:shallow]
1386
- # Generates shallow routes for nested resource(s). When placed on a parent resource,
1387
- # generates shallow routes for all nested resources.
1430
+ # :shallow
1431
+ # : Generates shallow routes for nested resource(s). When placed on a parent
1432
+ # resource, generates shallow routes for all nested resources.
1388
1433
  #
1389
- # resources :posts, shallow: true do
1390
- # resources :comments
1391
- # end
1434
+ # resources :posts, shallow: true do
1435
+ # resources :comments
1436
+ # end
1392
1437
  #
1393
- # Is the same as:
1438
+ # Is the same as:
1394
1439
  #
1395
- # resources :posts do
1396
- # resources :comments, except: [:show, :edit, :update, :destroy]
1397
- # end
1398
- # resources :comments, only: [:show, :edit, :update, :destroy]
1440
+ # resources :posts do
1441
+ # resources :comments, except: [:show, :edit, :update, :destroy]
1442
+ # end
1443
+ # resources :comments, only: [:show, :edit, :update, :destroy]
1399
1444
  #
1400
- # This allows URLs for resources that otherwise would be deeply nested such
1401
- # as a comment on a blog post like <tt>/posts/a-long-permalink/comments/1234</tt>
1402
- # to be shortened to just <tt>/comments/1234</tt>.
1445
+ # This allows URLs for resources that otherwise would be deeply nested such
1446
+ # as a comment on a blog post like `/posts/a-long-permalink/comments/1234`
1447
+ # to be shortened to just `/comments/1234`.
1403
1448
  #
1404
- # Set <tt>shallow: false</tt> on a child resource to ignore a parent's shallow parameter.
1449
+ # Set `shallow: false` on a child resource to ignore a parent's shallow
1450
+ # parameter.
1405
1451
  #
1406
- # [:shallow_path]
1407
- # Prefixes nested shallow routes with the specified path.
1452
+ # :shallow_path
1453
+ # : Prefixes nested shallow routes with the specified path.
1408
1454
  #
1409
- # scope shallow_path: "sekret" do
1410
- # resources :posts do
1411
- # resources :comments, shallow: true
1412
- # end
1413
- # end
1455
+ # scope shallow_path: "sekret" do
1456
+ # resources :posts do
1457
+ # resources :comments, shallow: true
1458
+ # end
1459
+ # end
1414
1460
  #
1415
- # The +comments+ resource here will have the following routes generated for it:
1461
+ # The `comments` resource here will have the following routes generated for
1462
+ # it:
1416
1463
  #
1417
- # post_comments GET /posts/:post_id/comments(.:format)
1418
- # post_comments POST /posts/:post_id/comments(.:format)
1419
- # new_post_comment GET /posts/:post_id/comments/new(.:format)
1420
- # edit_comment GET /sekret/comments/:id/edit(.:format)
1421
- # comment GET /sekret/comments/:id(.:format)
1422
- # comment PATCH/PUT /sekret/comments/:id(.:format)
1423
- # comment DELETE /sekret/comments/:id(.:format)
1464
+ # post_comments GET /posts/:post_id/comments(.:format)
1465
+ # post_comments POST /posts/:post_id/comments(.:format)
1466
+ # new_post_comment GET /posts/:post_id/comments/new(.:format)
1467
+ # edit_comment GET /sekret/comments/:id/edit(.:format)
1468
+ # comment GET /sekret/comments/:id(.:format)
1469
+ # comment PATCH/PUT /sekret/comments/:id(.:format)
1470
+ # comment DELETE /sekret/comments/:id(.:format)
1424
1471
  #
1425
- # [:shallow_prefix]
1426
- # Prefixes nested shallow route names with specified prefix.
1472
+ # :shallow_prefix
1473
+ # : Prefixes nested shallow route names with specified prefix.
1427
1474
  #
1428
- # scope shallow_prefix: "sekret" do
1429
- # resources :posts do
1430
- # resources :comments, shallow: true
1431
- # end
1432
- # end
1475
+ # scope shallow_prefix: "sekret" do
1476
+ # resources :posts do
1477
+ # resources :comments, shallow: true
1478
+ # end
1479
+ # end
1433
1480
  #
1434
- # The +comments+ resource here will have the following routes generated for it:
1481
+ # The `comments` resource here will have the following routes generated for
1482
+ # it:
1435
1483
  #
1436
- # post_comments GET /posts/:post_id/comments(.:format)
1437
- # post_comments POST /posts/:post_id/comments(.:format)
1438
- # new_post_comment GET /posts/:post_id/comments/new(.:format)
1439
- # edit_sekret_comment GET /comments/:id/edit(.:format)
1440
- # sekret_comment GET /comments/:id(.:format)
1441
- # sekret_comment PATCH/PUT /comments/:id(.:format)
1442
- # sekret_comment DELETE /comments/:id(.:format)
1484
+ # post_comments GET /posts/:post_id/comments(.:format)
1485
+ # post_comments POST /posts/:post_id/comments(.:format)
1486
+ # new_post_comment GET /posts/:post_id/comments/new(.:format)
1487
+ # edit_sekret_comment GET /comments/:id/edit(.:format)
1488
+ # sekret_comment GET /comments/:id(.:format)
1489
+ # sekret_comment PATCH/PUT /comments/:id(.:format)
1490
+ # sekret_comment DELETE /comments/:id(.:format)
1443
1491
  #
1444
- # [:format]
1445
- # Allows you to specify the default value for optional +format+
1446
- # segment or disable it by supplying +false+.
1492
+ # :format
1493
+ # : Allows you to specify the default value for optional `format` segment or
1494
+ # disable it by supplying `false`.
1447
1495
  #
1448
- # [:param]
1449
- # Allows you to override the default param name of +:id+ in the URL.
1496
+ # :param
1497
+ # : Allows you to override the default param name of `:id` in the URL.
1450
1498
  #
1451
- # === Examples
1452
1499
  #
1453
- # # routes call <tt>Admin::PostsController</tt>
1454
- # resources :posts, module: "admin"
1500
+ # ### Examples
1455
1501
  #
1456
- # # resource actions are at /admin/posts.
1457
- # resources :posts, path: "admin/posts"
1502
+ # # routes call +Admin::PostsController+
1503
+ # resources :posts, module: "admin"
1504
+ #
1505
+ # # resource actions are at /admin/posts.
1506
+ # resources :posts, path: "admin/posts"
1458
1507
  def resources(*resources, &block)
1459
1508
  options = resources.extract_options!.dup
1460
1509
 
@@ -1487,16 +1536,15 @@ module ActionDispatch
1487
1536
 
1488
1537
  # To add a route to the collection:
1489
1538
  #
1490
- # resources :photos do
1491
- # collection do
1492
- # get 'search'
1539
+ # resources :photos do
1540
+ # collection do
1541
+ # get 'search'
1542
+ # end
1493
1543
  # end
1494
- # end
1495
1544
  #
1496
- # This will enable Rails to recognize paths such as <tt>/photos/search</tt>
1497
- # with GET, and route to the search action of +PhotosController+. It will also
1498
- # create the <tt>search_photos_url</tt> and <tt>search_photos_path</tt>
1499
- # route helpers.
1545
+ # This will enable Rails to recognize paths such as `/photos/search` with GET,
1546
+ # and route to the search action of `PhotosController`. It will also create the
1547
+ # `search_photos_url` and `search_photos_path` route helpers.
1500
1548
  def collection(&block)
1501
1549
  unless resource_scope?
1502
1550
  raise ArgumentError, "can't use collection outside resource(s) scope"
@@ -1509,15 +1557,15 @@ module ActionDispatch
1509
1557
 
1510
1558
  # To add a member route, add a member block into the resource block:
1511
1559
  #
1512
- # resources :photos do
1513
- # member do
1514
- # get 'preview'
1560
+ # resources :photos do
1561
+ # member do
1562
+ # get 'preview'
1563
+ # end
1515
1564
  # end
1516
- # end
1517
1565
  #
1518
- # This will recognize <tt>/photos/1/preview</tt> with GET, and route to the
1519
- # preview action of +PhotosController+. It will also create the
1520
- # <tt>preview_photo_url</tt> and <tt>preview_photo_path</tt> helpers.
1566
+ # This will recognize `/photos/1/preview` with GET, and route to the preview
1567
+ # action of `PhotosController`. It will also create the `preview_photo_url` and
1568
+ # `preview_photo_path` helpers.
1521
1569
  def member(&block)
1522
1570
  unless resource_scope?
1523
1571
  raise ArgumentError, "can't use member outside resource(s) scope"
@@ -1584,29 +1632,28 @@ module ActionDispatch
1584
1632
  !parent_resource.singleton? && @scope[:shallow]
1585
1633
  end
1586
1634
 
1587
- # Loads another routes file with the given +name+ located inside the
1588
- # +config/routes+ directory. In that file, you can use the normal
1589
- # routing DSL, but <i>do not</i> surround it with a
1590
- # +Rails.application.routes.draw+ block.
1591
- #
1592
- # # config/routes.rb
1593
- # Rails.application.routes.draw do
1594
- # draw :admin # Loads `config/routes/admin.rb`
1595
- # draw "third_party/some_gem" # Loads `config/routes/third_party/some_gem.rb`
1596
- # end
1597
- #
1598
- # # config/routes/admin.rb
1599
- # namespace :admin do
1600
- # resources :accounts
1601
- # end
1602
- #
1603
- # # config/routes/third_party/some_gem.rb
1604
- # mount SomeGem::Engine, at: "/some_gem"
1605
- #
1606
- # <b>CAUTION:</b> Use this feature with care. Having multiple routes
1607
- # files can negatively impact discoverability and readability. For most
1608
- # applications — even those with a few hundred routes — it's easier for
1609
- # developers to have a single routes file.
1635
+ # Loads another routes file with the given `name` located inside the
1636
+ # `config/routes` directory. In that file, you can use the normal routing DSL,
1637
+ # but *do not* surround it with a `Rails.application.routes.draw` block.
1638
+ #
1639
+ # # config/routes.rb
1640
+ # Rails.application.routes.draw do
1641
+ # draw :admin # Loads `config/routes/admin.rb`
1642
+ # draw "third_party/some_gem" # Loads `config/routes/third_party/some_gem.rb`
1643
+ # end
1644
+ #
1645
+ # # config/routes/admin.rb
1646
+ # namespace :admin do
1647
+ # resources :accounts
1648
+ # end
1649
+ #
1650
+ # # config/routes/third_party/some_gem.rb
1651
+ # mount SomeGem::Engine, at: "/some_gem"
1652
+ #
1653
+ # **CAUTION:** Use this feature with care. Having multiple routes files can
1654
+ # negatively impact discoverability and readability. For most applications —
1655
+ # even those with a few hundred routes it's easier for developers to have a
1656
+ # single routes file.
1610
1657
  def draw(name)
1611
1658
  path = @draw_paths.find do |_path|
1612
1659
  File.exist? "#{_path}/#{name}.rb"
@@ -1623,12 +1670,12 @@ module ActionDispatch
1623
1670
  instance_eval(File.read(route_path), route_path.to_s)
1624
1671
  end
1625
1672
 
1626
- # Matches a URL pattern to one or more routes.
1627
- # For more information, see match[rdoc-ref:Base#match].
1673
+ # Matches a URL pattern to one or more routes. For more information, see
1674
+ # [match](rdoc-ref:Base#match).
1628
1675
  #
1629
- # match 'path' => 'controller#action', via: :patch
1630
- # match 'path', to: 'controller#action', via: :post
1631
- # match 'path', 'otherpath', on: :member, via: :get
1676
+ # match 'path' => 'controller#action', via: :patch
1677
+ # match 'path', to: 'controller#action', via: :post
1678
+ # match 'path', 'otherpath', on: :member, via: :get
1632
1679
  def match(path, *rest, &block)
1633
1680
  if rest.empty? && Hash === path
1634
1681
  options = path
@@ -1640,7 +1687,7 @@ module ActionDispatch
1640
1687
  when Symbol
1641
1688
  options[:action] = to
1642
1689
  when String
1643
- if /#/.match?(to)
1690
+ if to.include?("#")
1644
1691
  options[:to] = to
1645
1692
  else
1646
1693
  options[:controller] = to
@@ -1665,17 +1712,17 @@ module ActionDispatch
1665
1712
 
1666
1713
  # You can specify what Rails should route "/" to with the root method:
1667
1714
  #
1668
- # root to: 'pages#main'
1715
+ # root to: 'pages#main'
1669
1716
  #
1670
- # For options, see +match+, as +root+ uses it internally.
1717
+ # For options, see `match`, as `root` uses it internally.
1671
1718
  #
1672
1719
  # You can also pass a string which will expand
1673
1720
  #
1674
- # root 'pages#main'
1721
+ # root 'pages#main'
1675
1722
  #
1676
- # You should put the root route at the top of <tt>config/routes.rb</tt>,
1677
- # because this means it will be matched first. As this is the most popular route
1678
- # of most Rails applications, this is beneficial.
1723
+ # You should put the root route at the top of `config/routes.rb`, because this
1724
+ # means it will be matched first. As this is the most popular route of most
1725
+ # Rails applications, this is beneficial.
1679
1726
  def root(path, options = {})
1680
1727
  if path.is_a?(String)
1681
1728
  options[:to] = path
@@ -1853,9 +1900,9 @@ module ActionDispatch
1853
1900
  candidate = action_name.select(&:present?).join("_")
1854
1901
 
1855
1902
  unless candidate.empty?
1856
- # If a name was not explicitly given, we check if it is valid
1857
- # and return nil in case it isn't. Otherwise, we pass the invalid name
1858
- # forward so the underlying router engine treats it and raises an exception.
1903
+ # If a name was not explicitly given, we check if it is valid and return nil in
1904
+ # case it isn't. Otherwise, we pass the invalid name forward so the underlying
1905
+ # router engine treats it and raises an exception.
1859
1906
  if as.nil?
1860
1907
  candidate unless !candidate.match?(/\A[_a-z]/i) || has_named_route?(candidate)
1861
1908
  else
@@ -1978,7 +2025,7 @@ module ActionDispatch
1978
2025
  name_for_action(options.delete(:as), action)
1979
2026
  end
1980
2027
 
1981
- path = Mapping.normalize_path URI::DEFAULT_PARSER.escape(path), formatted
2028
+ path = Mapping.normalize_path RFC2396_PARSER.escape(path), formatted
1982
2029
  ast = Journey::Parser.parse path
1983
2030
 
1984
2031
  mapping = Mapping.build(@scope, @set, ast, controller, default_action, to, via, formatted, options_constraints, anchor, options)
@@ -1991,83 +2038,81 @@ module ActionDispatch
1991
2038
  end
1992
2039
  end
1993
2040
 
1994
- # Routing Concerns allow you to declare common routes that can be reused
1995
- # inside others resources and routes.
2041
+ # Routing Concerns allow you to declare common routes that can be reused inside
2042
+ # others resources and routes.
1996
2043
  #
1997
- # concern :commentable do
1998
- # resources :comments
1999
- # end
2044
+ # concern :commentable do
2045
+ # resources :comments
2046
+ # end
2000
2047
  #
2001
- # concern :image_attachable do
2002
- # resources :images, only: :index
2003
- # end
2048
+ # concern :image_attachable do
2049
+ # resources :images, only: :index
2050
+ # end
2004
2051
  #
2005
2052
  # These concerns are used in Resources routing:
2006
2053
  #
2007
- # resources :messages, concerns: [:commentable, :image_attachable]
2054
+ # resources :messages, concerns: [:commentable, :image_attachable]
2008
2055
  #
2009
2056
  # or in a scope or namespace:
2010
2057
  #
2011
- # namespace :posts do
2012
- # concerns :commentable
2013
- # end
2058
+ # namespace :posts do
2059
+ # concerns :commentable
2060
+ # end
2014
2061
  module Concerns
2015
2062
  # Define a routing concern using a name.
2016
2063
  #
2017
- # Concerns may be defined inline, using a block, or handled by
2018
- # another object, by passing that object as the second parameter.
2064
+ # Concerns may be defined inline, using a block, or handled by another object,
2065
+ # by passing that object as the second parameter.
2019
2066
  #
2020
- # The concern object, if supplied, should respond to <tt>call</tt>,
2021
- # which will receive two parameters:
2067
+ # The concern object, if supplied, should respond to `call`, which will receive
2068
+ # two parameters:
2022
2069
  #
2023
- # * The current mapper
2024
- # * A hash of options which the concern object may use
2070
+ # * The current mapper
2071
+ # * A hash of options which the concern object may use
2025
2072
  #
2026
- # Options may also be used by concerns defined in a block by accepting
2027
- # a block parameter. So, using a block, you might do something as
2028
- # simple as limit the actions available on certain resources, passing
2029
- # standard resource options through the concern:
2073
+ # Options may also be used by concerns defined in a block by accepting a block
2074
+ # parameter. So, using a block, you might do something as simple as limit the
2075
+ # actions available on certain resources, passing standard resource options
2076
+ # through the concern:
2030
2077
  #
2031
- # concern :commentable do |options|
2032
- # resources :comments, options
2033
- # end
2078
+ # concern :commentable do |options|
2079
+ # resources :comments, options
2080
+ # end
2034
2081
  #
2035
- # resources :posts, concerns: :commentable
2036
- # resources :archived_posts do
2037
- # # Don't allow comments on archived posts
2038
- # concerns :commentable, only: [:index, :show]
2039
- # end
2082
+ # resources :posts, concerns: :commentable
2083
+ # resources :archived_posts do
2084
+ # # Don't allow comments on archived posts
2085
+ # concerns :commentable, only: [:index, :show]
2086
+ # end
2040
2087
  #
2041
- # Or, using a callable object, you might implement something more
2042
- # specific to your application, which would be out of place in your
2043
- # routes file.
2088
+ # Or, using a callable object, you might implement something more specific to
2089
+ # your application, which would be out of place in your routes file.
2044
2090
  #
2045
- # # purchasable.rb
2046
- # class Purchasable
2047
- # def initialize(defaults = {})
2048
- # @defaults = defaults
2049
- # end
2091
+ # # purchasable.rb
2092
+ # class Purchasable
2093
+ # def initialize(defaults = {})
2094
+ # @defaults = defaults
2095
+ # end
2050
2096
  #
2051
- # def call(mapper, options = {})
2052
- # options = @defaults.merge(options)
2053
- # mapper.resources :purchases
2054
- # mapper.resources :receipts
2055
- # mapper.resources :returns if options[:returnable]
2097
+ # def call(mapper, options = {})
2098
+ # options = @defaults.merge(options)
2099
+ # mapper.resources :purchases
2100
+ # mapper.resources :receipts
2101
+ # mapper.resources :returns if options[:returnable]
2102
+ # end
2056
2103
  # end
2057
- # end
2058
2104
  #
2059
- # # routes.rb
2060
- # concern :purchasable, Purchasable.new(returnable: true)
2105
+ # # routes.rb
2106
+ # concern :purchasable, Purchasable.new(returnable: true)
2061
2107
  #
2062
- # resources :toys, concerns: :purchasable
2063
- # resources :electronics, concerns: :purchasable
2064
- # resources :pets do
2065
- # concerns :purchasable, returnable: false
2066
- # end
2108
+ # resources :toys, concerns: :purchasable
2109
+ # resources :electronics, concerns: :purchasable
2110
+ # resources :pets do
2111
+ # concerns :purchasable, returnable: false
2112
+ # end
2067
2113
  #
2068
- # Any routing helpers can be used inside a concern. If using a
2069
- # callable, they're accessible from the Mapper that's passed to
2070
- # <tt>call</tt>.
2114
+ # Any routing helpers can be used inside a concern. If using a callable, they're
2115
+ # accessible from the Mapper that's passed to `call`.
2071
2116
  def concern(name, callable = nil, &block)
2072
2117
  callable ||= lambda { |mapper, options| mapper.instance_exec(options, &block) }
2073
2118
  @concerns[name] = callable
@@ -2075,15 +2120,15 @@ module ActionDispatch
2075
2120
 
2076
2121
  # Use the named concerns
2077
2122
  #
2078
- # resources :posts do
2079
- # concerns :commentable
2080
- # end
2123
+ # resources :posts do
2124
+ # concerns :commentable
2125
+ # end
2081
2126
  #
2082
2127
  # Concerns also work in any routes helper that you want to use:
2083
2128
  #
2084
- # namespace :posts do
2085
- # concerns :commentable
2086
- # end
2129
+ # namespace :posts do
2130
+ # concerns :commentable
2131
+ # end
2087
2132
  def concerns(*args)
2088
2133
  options = args.extract_options!
2089
2134
  args.flatten.each do |name|
@@ -2097,53 +2142,55 @@ module ActionDispatch
2097
2142
  end
2098
2143
 
2099
2144
  module CustomUrls
2100
- # Define custom URL helpers that will be added to the application's
2101
- # routes. This allows you to override and/or replace the default behavior
2102
- # of routing helpers, e.g:
2145
+ # Define custom URL helpers that will be added to the application's routes. This
2146
+ # allows you to override and/or replace the default behavior of routing helpers,
2147
+ # e.g:
2103
2148
  #
2104
- # direct :homepage do
2105
- # "https://rubyonrails.org"
2106
- # end
2149
+ # direct :homepage do
2150
+ # "https://rubyonrails.org"
2151
+ # end
2107
2152
  #
2108
- # direct :commentable do |model|
2109
- # [ model, anchor: model.dom_id ]
2110
- # end
2153
+ # direct :commentable do |model|
2154
+ # [ model, anchor: model.dom_id ]
2155
+ # end
2111
2156
  #
2112
- # direct :main do
2113
- # { controller: "pages", action: "index", subdomain: "www" }
2114
- # end
2157
+ # direct :main do
2158
+ # { controller: "pages", action: "index", subdomain: "www" }
2159
+ # end
2115
2160
  #
2116
- # The return value from the block passed to +direct+ must be a valid set of
2117
- # arguments for +url_for+ which will actually build the URL string. This can
2118
- # be one of the following:
2161
+ # The return value from the block passed to `direct` must be a valid set of
2162
+ # arguments for `url_for` which will actually build the URL string. This can be
2163
+ # one of the following:
2119
2164
  #
2120
- # * A string, which is treated as a generated URL
2121
- # * A hash, e.g. <tt>{ controller: "pages", action: "index" }</tt>
2122
- # * An array, which is passed to +polymorphic_url+
2123
- # * An Active Model instance
2124
- # * An Active Model class
2165
+ # * A string, which is treated as a generated URL
2166
+ # * A hash, e.g. `{ controller: "pages", action: "index" }`
2167
+ # * An array, which is passed to `polymorphic_url`
2168
+ # * An Active Model instance
2169
+ # * An Active Model class
2125
2170
  #
2126
- # NOTE: Other URL helpers can be called in the block but be careful not to invoke
2127
- # your custom URL helper again otherwise it will result in a stack overflow error.
2128
2171
  #
2129
- # You can also specify default options that will be passed through to
2130
- # your URL helper definition, e.g:
2172
+ # NOTE: Other URL helpers can be called in the block but be careful not to
2173
+ # invoke your custom URL helper again otherwise it will result in a stack
2174
+ # overflow error.
2131
2175
  #
2132
- # direct :browse, page: 1, size: 10 do |options|
2133
- # [ :products, options.merge(params.permit(:page, :size).to_h.symbolize_keys) ]
2134
- # end
2176
+ # You can also specify default options that will be passed through to your URL
2177
+ # helper definition, e.g:
2135
2178
  #
2136
- # In this instance the +params+ object comes from the context in which the
2137
- # block is executed, e.g. generating a URL inside a controller action or a view.
2138
- # If the block is executed where there isn't a +params+ object such as this:
2179
+ # direct :browse, page: 1, size: 10 do |options|
2180
+ # [ :products, options.merge(params.permit(:page, :size).to_h.symbolize_keys) ]
2181
+ # end
2182
+ #
2183
+ # In this instance the `params` object comes from the context in which the block
2184
+ # is executed, e.g. generating a URL inside a controller action or a view. If
2185
+ # the block is executed where there isn't a `params` object such as this:
2139
2186
  #
2140
- # Rails.application.routes.url_helpers.browse_path
2187
+ # Rails.application.routes.url_helpers.browse_path
2141
2188
  #
2142
- # then it will raise a +NameError+. Because of this you need to be aware of the
2189
+ # then it will raise a `NameError`. Because of this you need to be aware of the
2143
2190
  # context in which you will use your custom URL helper when defining it.
2144
2191
  #
2145
- # NOTE: The +direct+ method can't be used inside of a scope block such as
2146
- # +namespace+ or +scope+ and will raise an error if it detects that it is.
2192
+ # NOTE: The `direct` method can't be used inside of a scope block such as
2193
+ # `namespace` or `scope` and will raise an error if it detects that it is.
2147
2194
  def direct(name, options = {}, &block)
2148
2195
  unless @scope.root?
2149
2196
  raise RuntimeError, "The direct method can't be used inside a routes scope block"
@@ -2152,50 +2199,50 @@ module ActionDispatch
2152
2199
  @set.add_url_helper(name, options, &block)
2153
2200
  end
2154
2201
 
2155
- # Define custom polymorphic mappings of models to URLs. This alters the
2156
- # behavior of +polymorphic_url+ and consequently the behavior of
2157
- # +link_to+ and +form_for+ when passed a model instance, e.g:
2202
+ # Define custom polymorphic mappings of models to URLs. This alters the behavior
2203
+ # of `polymorphic_url` and consequently the behavior of `link_to` and `form_for`
2204
+ # when passed a model instance, e.g:
2158
2205
  #
2159
- # resource :basket
2206
+ # resource :basket
2160
2207
  #
2161
- # resolve "Basket" do
2162
- # [:basket]
2163
- # end
2208
+ # resolve "Basket" do
2209
+ # [:basket]
2210
+ # end
2164
2211
  #
2165
- # This will now generate "/basket" when a +Basket+ instance is passed to
2166
- # +link_to+ or +form_for+ instead of the standard "/baskets/:id".
2212
+ # This will now generate "/basket" when a `Basket` instance is passed to
2213
+ # `link_to` or `form_for` instead of the standard "/baskets/:id".
2167
2214
  #
2168
- # NOTE: This custom behavior only applies to simple polymorphic URLs where
2169
- # a single model instance is passed and not more complicated forms, e.g:
2215
+ # NOTE: This custom behavior only applies to simple polymorphic URLs where a
2216
+ # single model instance is passed and not more complicated forms, e.g:
2170
2217
  #
2171
- # # config/routes.rb
2172
- # resource :profile
2173
- # namespace :admin do
2174
- # resources :users
2175
- # end
2218
+ # # config/routes.rb
2219
+ # resource :profile
2220
+ # namespace :admin do
2221
+ # resources :users
2222
+ # end
2176
2223
  #
2177
- # resolve("User") { [:profile] }
2224
+ # resolve("User") { [:profile] }
2178
2225
  #
2179
- # # app/views/application/_menu.html.erb
2180
- # link_to "Profile", @current_user
2181
- # link_to "Profile", [:admin, @current_user]
2226
+ # # app/views/application/_menu.html.erb
2227
+ # link_to "Profile", @current_user
2228
+ # link_to "Profile", [:admin, @current_user]
2182
2229
  #
2183
- # The first +link_to+ will generate "/profile" but the second will generate
2184
- # the standard polymorphic URL of "/admin/users/1".
2230
+ # The first `link_to` will generate "/profile" but the second will generate the
2231
+ # standard polymorphic URL of "/admin/users/1".
2185
2232
  #
2186
- # You can pass options to a polymorphic mapping - the arity for the block
2187
- # needs to be two as the instance is passed as the first argument, e.g:
2233
+ # You can pass options to a polymorphic mapping - the arity for the block needs
2234
+ # to be two as the instance is passed as the first argument, e.g:
2188
2235
  #
2189
- # resolve "Basket", anchor: "items" do |basket, options|
2190
- # [:basket, options]
2191
- # end
2236
+ # resolve "Basket", anchor: "items" do |basket, options|
2237
+ # [:basket, options]
2238
+ # end
2192
2239
  #
2193
- # This generates the URL "/basket#items" because when the last item in an
2194
- # array passed to +polymorphic_url+ is a hash then it's treated as options
2195
- # to the URL helper that gets called.
2240
+ # This generates the URL "/basket#items" because when the last item in an array
2241
+ # passed to `polymorphic_url` is a hash then it's treated as options to the URL
2242
+ # helper that gets called.
2196
2243
  #
2197
- # NOTE: The +resolve+ method can't be used inside of a scope block such as
2198
- # +namespace+ or +scope+ and will raise an error if it detects that it is.
2244
+ # NOTE: The `resolve` method can't be used inside of a scope block such as
2245
+ # `namespace` or `scope` and will raise an error if it detects that it is.
2199
2246
  def resolve(*args, &block)
2200
2247
  unless @scope.root?
2201
2248
  raise RuntimeError, "The resolve method can't be used inside a routes scope block"