actionpack 7.0.4 → 7.1.5.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 (140) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +495 -257
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -4
  5. data/lib/abstract_controller/base.rb +20 -11
  6. data/lib/abstract_controller/caching/fragments.rb +2 -0
  7. data/lib/abstract_controller/callbacks.rb +31 -6
  8. data/lib/abstract_controller/deprecator.rb +7 -0
  9. data/lib/abstract_controller/helpers.rb +75 -28
  10. data/lib/abstract_controller/railties/routes_helpers.rb +1 -16
  11. data/lib/abstract_controller/rendering.rb +12 -14
  12. data/lib/abstract_controller/translation.rb +11 -6
  13. data/lib/abstract_controller/url_for.rb +2 -0
  14. data/lib/abstract_controller.rb +6 -0
  15. data/lib/action_controller/api.rb +6 -4
  16. data/lib/action_controller/base.rb +3 -17
  17. data/lib/action_controller/caching.rb +2 -0
  18. data/lib/action_controller/deprecator.rb +7 -0
  19. data/lib/action_controller/form_builder.rb +2 -0
  20. data/lib/action_controller/log_subscriber.rb +16 -4
  21. data/lib/action_controller/metal/basic_implicit_render.rb +3 -1
  22. data/lib/action_controller/metal/conditional_get.rb +121 -123
  23. data/lib/action_controller/metal/content_security_policy.rb +5 -5
  24. data/lib/action_controller/metal/data_streaming.rb +20 -18
  25. data/lib/action_controller/metal/default_headers.rb +2 -0
  26. data/lib/action_controller/metal/etag_with_flash.rb +3 -1
  27. data/lib/action_controller/metal/etag_with_template_digest.rb +2 -0
  28. data/lib/action_controller/metal/exceptions.rb +8 -0
  29. data/lib/action_controller/metal/head.rb +9 -7
  30. data/lib/action_controller/metal/helpers.rb +3 -14
  31. data/lib/action_controller/metal/http_authentication.rb +15 -9
  32. data/lib/action_controller/metal/implicit_render.rb +5 -3
  33. data/lib/action_controller/metal/instrumentation.rb +8 -1
  34. data/lib/action_controller/metal/live.rb +25 -1
  35. data/lib/action_controller/metal/mime_responds.rb +2 -2
  36. data/lib/action_controller/metal/params_wrapper.rb +4 -2
  37. data/lib/action_controller/metal/permissions_policy.rb +2 -2
  38. data/lib/action_controller/metal/redirecting.rb +29 -8
  39. data/lib/action_controller/metal/renderers.rb +4 -4
  40. data/lib/action_controller/metal/rendering.rb +114 -9
  41. data/lib/action_controller/metal/request_forgery_protection.rb +144 -53
  42. data/lib/action_controller/metal/rescue.rb +6 -3
  43. data/lib/action_controller/metal/streaming.rb +71 -31
  44. data/lib/action_controller/metal/strong_parameters.rb +200 -103
  45. data/lib/action_controller/metal/url_for.rb +9 -4
  46. data/lib/action_controller/metal.rb +79 -21
  47. data/lib/action_controller/railtie.rb +24 -10
  48. data/lib/action_controller/renderer.rb +99 -85
  49. data/lib/action_controller/test_case.rb +18 -8
  50. data/lib/action_controller.rb +13 -3
  51. data/lib/action_dispatch/constants.rb +32 -0
  52. data/lib/action_dispatch/deprecator.rb +7 -0
  53. data/lib/action_dispatch/http/cache.rb +9 -11
  54. data/lib/action_dispatch/http/content_security_policy.rb +35 -13
  55. data/lib/action_dispatch/http/filter_parameters.rb +23 -32
  56. data/lib/action_dispatch/http/headers.rb +3 -1
  57. data/lib/action_dispatch/http/mime_negotiation.rb +22 -22
  58. data/lib/action_dispatch/http/mime_type.rb +37 -11
  59. data/lib/action_dispatch/http/mime_types.rb +3 -1
  60. data/lib/action_dispatch/http/parameters.rb +1 -1
  61. data/lib/action_dispatch/http/permissions_policy.rb +38 -23
  62. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  63. data/lib/action_dispatch/http/request.rb +85 -32
  64. data/lib/action_dispatch/http/response.rb +80 -63
  65. data/lib/action_dispatch/http/upload.rb +15 -2
  66. data/lib/action_dispatch/journey/formatter.rb +8 -2
  67. data/lib/action_dispatch/journey/path/pattern.rb +14 -14
  68. data/lib/action_dispatch/journey/route.rb +3 -2
  69. data/lib/action_dispatch/journey/router.rb +9 -8
  70. data/lib/action_dispatch/journey/routes.rb +2 -2
  71. data/lib/action_dispatch/log_subscriber.rb +23 -0
  72. data/lib/action_dispatch/middleware/actionable_exceptions.rb +5 -6
  73. data/lib/action_dispatch/middleware/assume_ssl.rb +24 -0
  74. data/lib/action_dispatch/middleware/callbacks.rb +2 -0
  75. data/lib/action_dispatch/middleware/cookies.rb +108 -117
  76. data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -25
  77. data/lib/action_dispatch/middleware/debug_locks.rb +4 -1
  78. data/lib/action_dispatch/middleware/debug_view.rb +7 -2
  79. data/lib/action_dispatch/middleware/exception_wrapper.rb +186 -27
  80. data/lib/action_dispatch/middleware/executor.rb +7 -1
  81. data/lib/action_dispatch/middleware/flash.rb +7 -0
  82. data/lib/action_dispatch/middleware/host_authorization.rb +18 -8
  83. data/lib/action_dispatch/middleware/public_exceptions.rb +5 -3
  84. data/lib/action_dispatch/middleware/reloader.rb +7 -5
  85. data/lib/action_dispatch/middleware/remote_ip.rb +21 -20
  86. data/lib/action_dispatch/middleware/request_id.rb +4 -2
  87. data/lib/action_dispatch/middleware/server_timing.rb +4 -4
  88. data/lib/action_dispatch/middleware/session/abstract_store.rb +5 -0
  89. data/lib/action_dispatch/middleware/session/cache_store.rb +2 -0
  90. data/lib/action_dispatch/middleware/session/cookie_store.rb +11 -5
  91. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +3 -1
  92. data/lib/action_dispatch/middleware/show_exceptions.rb +39 -22
  93. data/lib/action_dispatch/middleware/ssl.rb +18 -6
  94. data/lib/action_dispatch/middleware/stack.rb +7 -2
  95. data/lib/action_dispatch/middleware/static.rb +14 -10
  96. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
  97. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +4 -4
  98. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
  99. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -3
  100. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -3
  101. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +7 -7
  102. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
  103. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +17 -0
  104. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +16 -12
  105. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -1
  106. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
  107. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +4 -4
  108. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
  109. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
  110. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +3 -0
  111. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +59 -41
  112. data/lib/action_dispatch/railtie.rb +13 -4
  113. data/lib/action_dispatch/request/session.rb +16 -6
  114. data/lib/action_dispatch/request/utils.rb +8 -3
  115. data/lib/action_dispatch/routing/inspector.rb +54 -6
  116. data/lib/action_dispatch/routing/mapper.rb +97 -26
  117. data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -0
  118. data/lib/action_dispatch/routing/redirection.rb +15 -6
  119. data/lib/action_dispatch/routing/route_set.rb +53 -23
  120. data/lib/action_dispatch/routing/routes_proxy.rb +10 -15
  121. data/lib/action_dispatch/routing/url_for.rb +26 -22
  122. data/lib/action_dispatch/routing.rb +7 -7
  123. data/lib/action_dispatch/system_test_case.rb +3 -3
  124. data/lib/action_dispatch/system_testing/browser.rb +25 -19
  125. data/lib/action_dispatch/system_testing/driver.rb +15 -23
  126. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +27 -16
  127. data/lib/action_dispatch/testing/assertion_response.rb +1 -1
  128. data/lib/action_dispatch/testing/assertions/response.rb +14 -7
  129. data/lib/action_dispatch/testing/assertions/routing.rb +67 -28
  130. data/lib/action_dispatch/testing/assertions.rb +3 -1
  131. data/lib/action_dispatch/testing/integration.rb +27 -17
  132. data/lib/action_dispatch/testing/request_encoder.rb +4 -1
  133. data/lib/action_dispatch/testing/test_process.rb +4 -3
  134. data/lib/action_dispatch/testing/test_request.rb +1 -1
  135. data/lib/action_dispatch/testing/test_response.rb +23 -9
  136. data/lib/action_dispatch.rb +41 -4
  137. data/lib/action_pack/gem_version.rb +4 -4
  138. data/lib/action_pack/version.rb +1 -1
  139. data/lib/action_pack.rb +1 -1
  140. metadata +68 -32
@@ -10,8 +10,20 @@ require "action_dispatch/routing/endpoint"
10
10
  module ActionDispatch
11
11
  module Routing
12
12
  class Mapper
13
+ class BacktraceCleaner < ActiveSupport::BacktraceCleaner # :nodoc:
14
+ def initialize
15
+ super
16
+ remove_silencers!
17
+ add_core_silencer
18
+ add_stdlib_silencer
19
+ end
20
+ end
21
+
13
22
  URL_OPTIONS = [:protocol, :subdomain, :domain, :host, :port]
14
23
 
24
+ cattr_accessor :route_source_locations, instance_accessor: false, default: false
25
+ cattr_accessor :backtrace_cleaner, instance_accessor: false, default: BacktraceCleaner.new
26
+
15
27
  class Constraints < Routing::Endpoint # :nodoc:
16
28
  attr_reader :app, :constraints
17
29
 
@@ -43,7 +55,7 @@ module ActionDispatch
43
55
  end
44
56
 
45
57
  def serve(req)
46
- return [ 404, { "X-Cascade" => "pass" }, [] ] unless matches?(req)
58
+ return [ 404, { Constants::X_CASCADE => "pass" }, [] ] unless matches?(req)
47
59
 
48
60
  @strategy.call @app, req
49
61
  end
@@ -170,7 +182,7 @@ module ActionDispatch
170
182
  Journey::Route.new(name: name, app: application, path: path, constraints: conditions,
171
183
  required_defaults: required_defaults, defaults: defaults,
172
184
  request_method_match: request_method, precedence: precedence,
173
- scope_options: scope_options, internal: @internal)
185
+ scope_options: scope_options, internal: @internal, source_location: route_source_location)
174
186
  end
175
187
 
176
188
  def application
@@ -214,9 +226,21 @@ module ActionDispatch
214
226
  if to.respond_to?(:action) || to.respond_to?(:call)
215
227
  options
216
228
  else
217
- to_endpoint = split_to to
218
- controller = to_endpoint[0] || default_controller
219
- action = to_endpoint[1] || default_action
229
+ if to.nil?
230
+ controller = default_controller
231
+ action = default_action
232
+ elsif to.is_a?(String)
233
+ if to.include?("#")
234
+ to_endpoint = to.split("#").map!(&:-@)
235
+ controller = to_endpoint[0]
236
+ action = to_endpoint[1]
237
+ else
238
+ controller = default_controller
239
+ action = to
240
+ end
241
+ else
242
+ raise ArgumentError, ":to must respond to `action` or `call`, or it must be a String that includes '#', or the controller should be implicit"
243
+ end
220
244
 
221
245
  controller = add_controller_module(controller, modyoule)
222
246
 
@@ -305,14 +329,6 @@ module ActionDispatch
305
329
  hash
306
330
  end
307
331
 
308
- def split_to(to)
309
- if /#/.match?(to)
310
- to.split("#").map!(&:-@)
311
- else
312
- []
313
- end
314
- end
315
-
316
332
  def add_controller_module(controller, modyoule)
317
333
  if modyoule && !controller.is_a?(Regexp)
318
334
  if controller&.start_with?("/")
@@ -356,6 +372,38 @@ module ActionDispatch
356
372
  def dispatcher(raise_on_name_error)
357
373
  Routing::RouteSet::Dispatcher.new raise_on_name_error
358
374
  end
375
+
376
+ if Thread.respond_to?(:each_caller_location)
377
+ def route_source_location
378
+ if Mapper.route_source_locations
379
+ action_dispatch_dir = File.expand_path("..", __dir__)
380
+ Thread.each_caller_location do |location|
381
+ next if location.path.start_with?(action_dispatch_dir)
382
+
383
+ cleaned_path = Mapper.backtrace_cleaner.clean_frame(location.path)
384
+ next if cleaned_path.nil?
385
+
386
+ return "#{cleaned_path}:#{location.lineno}"
387
+ end
388
+ nil
389
+ end
390
+ end
391
+ else
392
+ def route_source_location
393
+ if Mapper.route_source_locations
394
+ action_dispatch_dir = File.expand_path("..", __dir__)
395
+ caller_locations.each do |location|
396
+ next if location.path.start_with?(action_dispatch_dir)
397
+
398
+ cleaned_path = Mapper.backtrace_cleaner.clean_frame(location.path)
399
+ next if cleaned_path.nil?
400
+
401
+ return "#{cleaned_path}:#{location.lineno}"
402
+ end
403
+ nil
404
+ end
405
+ end
406
+ end
359
407
  end
360
408
 
361
409
  # Invokes Journey::Router::Utils.normalize_path, then ensures that
@@ -652,7 +700,7 @@ module ActionDispatch
652
700
 
653
701
  script_namer = ->(options) do
654
702
  prefix_options = options.slice(*_route.segment_keys)
655
- prefix_options[:relative_url_root] = ""
703
+ prefix_options[:script_name] = "" if options[:original_script_name]
656
704
 
657
705
  if options[:_recall]
658
706
  prefix_options.reverse_merge!(options[:_recall].slice(*_route.segment_keys))
@@ -669,7 +717,7 @@ module ActionDispatch
669
717
  def optimize_routes_generation?; false; end
670
718
 
671
719
  define_method :find_script_name do |options|
672
- if options.key? :script_name
720
+ if options.key?(:script_name) && options[:script_name].present?
673
721
  super(options)
674
722
  else
675
723
  script_namer.call(options)
@@ -748,7 +796,7 @@ module ActionDispatch
748
796
  # end
749
797
  #
750
798
  # This will create a number of routes for each of the posts and comments
751
- # controller. For <tt>Admin::PostsController</tt>, Rails will create:
799
+ # controller. For +Admin::PostsController+, \Rails will create:
752
800
  #
753
801
  # GET /admin/posts
754
802
  # GET /admin/posts/new
@@ -759,7 +807,7 @@ module ActionDispatch
759
807
  # DELETE /admin/posts/1
760
808
  #
761
809
  # If you want to route /posts (without the prefix /admin) to
762
- # <tt>Admin::PostsController</tt>, you could use
810
+ # +Admin::PostsController+, you could use
763
811
  #
764
812
  # scope module: "admin" do
765
813
  # resources :posts
@@ -808,7 +856,7 @@ module ActionDispatch
808
856
  #
809
857
  # Takes same options as <tt>Base#match</tt> and <tt>Resources#resources</tt>.
810
858
  #
811
- # # route /posts (without the prefix /admin) to <tt>Admin::PostsController</tt>
859
+ # # route /posts (without the prefix /admin) to +Admin::PostsController+
812
860
  # scope module: "admin" do
813
861
  # resources :posts
814
862
  # end
@@ -917,7 +965,7 @@ module ActionDispatch
917
965
  # resources :posts
918
966
  # end
919
967
  #
920
- # # maps to <tt>Sekret::PostsController</tt> rather than <tt>Admin::PostsController</tt>
968
+ # # maps to +Sekret::PostsController+ rather than +Admin::PostsController+
921
969
  # namespace :admin, module: "sekret" do
922
970
  # resources :posts
923
971
  # end
@@ -1318,7 +1366,7 @@ module ActionDispatch
1318
1366
  self
1319
1367
  end
1320
1368
 
1321
- # In Rails, a resourceful route provides a mapping between HTTP verbs
1369
+ # In \Rails, a resourceful route provides a mapping between HTTP verbs
1322
1370
  # and URLs and controller actions. By convention, each action also maps
1323
1371
  # to particular CRUD operations in a database. A single entry in the
1324
1372
  # routing file, such as
@@ -1450,7 +1498,7 @@ module ActionDispatch
1450
1498
  #
1451
1499
  # === Examples
1452
1500
  #
1453
- # # routes call <tt>Admin::PostsController</tt>
1501
+ # # routes call +Admin::PostsController+
1454
1502
  # resources :posts, module: "admin"
1455
1503
  #
1456
1504
  # # resource actions are at /admin/posts.
@@ -1493,7 +1541,7 @@ module ActionDispatch
1493
1541
  # end
1494
1542
  # end
1495
1543
  #
1496
- # This will enable Rails to recognize paths such as <tt>/photos/search</tt>
1544
+ # This will enable \Rails to recognize paths such as <tt>/photos/search</tt>
1497
1545
  # with GET, and route to the search action of +PhotosController+. It will also
1498
1546
  # create the <tt>search_photos_url</tt> and <tt>search_photos_path</tt>
1499
1547
  # route helpers.
@@ -1584,6 +1632,29 @@ module ActionDispatch
1584
1632
  !parent_resource.singleton? && @scope[:shallow]
1585
1633
  end
1586
1634
 
1635
+ # Loads another routes file with the given +name+ located inside the
1636
+ # +config/routes+ directory. In that file, you can use the normal
1637
+ # routing DSL, but <i>do not</i> surround it with a
1638
+ # +Rails.application.routes.draw+ block.
1639
+ #
1640
+ # # config/routes.rb
1641
+ # Rails.application.routes.draw do
1642
+ # draw :admin # Loads `config/routes/admin.rb`
1643
+ # draw "third_party/some_gem" # Loads `config/routes/third_party/some_gem.rb`
1644
+ # end
1645
+ #
1646
+ # # config/routes/admin.rb
1647
+ # namespace :admin do
1648
+ # resources :accounts
1649
+ # end
1650
+ #
1651
+ # # config/routes/third_party/some_gem.rb
1652
+ # mount SomeGem::Engine, at: "/some_gem"
1653
+ #
1654
+ # <b>CAUTION:</b> Use this feature with care. Having multiple routes
1655
+ # files can negatively impact discoverability and readability. For most
1656
+ # applications — even those with a few hundred routes — it's easier for
1657
+ # developers to have a single routes file.
1587
1658
  def draw(name)
1588
1659
  path = @draw_paths.find do |_path|
1589
1660
  File.exist? "#{_path}/#{name}.rb"
@@ -1617,7 +1688,7 @@ module ActionDispatch
1617
1688
  when Symbol
1618
1689
  options[:action] = to
1619
1690
  when String
1620
- if /#/.match?(to)
1691
+ if to.include?("#")
1621
1692
  options[:to] = to
1622
1693
  else
1623
1694
  options[:controller] = to
@@ -1640,7 +1711,7 @@ module ActionDispatch
1640
1711
  end
1641
1712
  end
1642
1713
 
1643
- # You can specify what Rails should route "/" to with the root method:
1714
+ # You can specify what \Rails should route "/" to with the root method:
1644
1715
  #
1645
1716
  # root to: 'pages#main'
1646
1717
  #
@@ -1652,7 +1723,7 @@ module ActionDispatch
1652
1723
  #
1653
1724
  # You should put the root route at the top of <tt>config/routes.rb</tt>,
1654
1725
  # because this means it will be matched first. As this is the most popular route
1655
- # of most Rails applications, this is beneficial.
1726
+ # of most \Rails applications, this is beneficial.
1656
1727
  def root(path, options = {})
1657
1728
  if path.is_a?(String)
1658
1729
  options[:to] = path
@@ -1955,7 +2026,7 @@ module ActionDispatch
1955
2026
  name_for_action(options.delete(:as), action)
1956
2027
  end
1957
2028
 
1958
- path = Mapping.normalize_path URI::DEFAULT_PARSER.escape(path), formatted
2029
+ path = Mapping.normalize_path RFC2396_PARSER.escape(path), formatted
1959
2030
  ast = Journey::Parser.parse path
1960
2031
 
1961
2032
  mapping = Mapping.build(@scope, @set, ast, controller, default_action, to, via, formatted, options_constraints, anchor, options)
@@ -2,6 +2,8 @@
2
2
 
3
3
  module ActionDispatch
4
4
  module Routing
5
+ # = Action Dispatch Routing \PolymorphicRoutes
6
+ #
5
7
  # Polymorphic URL helpers are methods for smart resolution to a named route call when
6
8
  # given an Active Record model instance. They are to be used in combination with
7
9
  # ActionController::Resources.
@@ -18,10 +18,19 @@ module ActionDispatch
18
18
  def redirect?; true; end
19
19
 
20
20
  def call(env)
21
- serve Request.new env
21
+ ActiveSupport::Notifications.instrument("redirect.action_dispatch") do |payload|
22
+ request = Request.new(env)
23
+ response = build_response(request)
24
+
25
+ payload[:status] = @status
26
+ payload[:location] = response.headers["Location"]
27
+ payload[:request] = request
28
+
29
+ response.to_a
30
+ end
22
31
  end
23
32
 
24
- def serve(req)
33
+ def build_response(req)
25
34
  uri = URI.parse(path(req.path_parameters, req))
26
35
 
27
36
  unless uri.host
@@ -38,15 +47,15 @@ module ActionDispatch
38
47
 
39
48
  req.commit_flash
40
49
 
41
- body = %(<html><body>You are being <a href="#{ERB::Util.unwrapped_html_escape(uri.to_s)}">redirected</a>.</body></html>)
50
+ body = ""
42
51
 
43
52
  headers = {
44
53
  "Location" => uri.to_s,
45
- "Content-Type" => "text/html",
54
+ "Content-Type" => "text/html; charset=#{ActionDispatch::Response.default_charset}",
46
55
  "Content-Length" => body.length.to_s
47
56
  }
48
57
 
49
- [ status, headers, [body] ]
58
+ ActionDispatch::Response.new(status, headers, body)
50
59
  end
51
60
 
52
61
  def path(params, request)
@@ -59,7 +68,7 @@ module ActionDispatch
59
68
 
60
69
  private
61
70
  def relative_path?(path)
62
- path && !path.empty? && path[0] != "/"
71
+ path && !path.empty? && !path.start_with?("/")
63
72
  end
64
73
 
65
74
  def escape(params)
@@ -34,20 +34,20 @@ module ActionDispatch
34
34
  if @raise_on_name_error
35
35
  raise
36
36
  else
37
- [404, { "X-Cascade" => "pass" }, []]
37
+ [404, { Constants::X_CASCADE => "pass" }, []]
38
38
  end
39
39
  end
40
40
 
41
- private
42
- def controller(req)
43
- req.controller_class
44
- rescue NameError => e
45
- raise ActionController::RoutingError, e.message, e.backtrace
46
- end
41
+ private
42
+ def controller(req)
43
+ req.controller_class
44
+ rescue NameError => e
45
+ raise ActionController::RoutingError, e.message, e.backtrace
46
+ end
47
47
 
48
- def dispatch(controller, action, req, res)
49
- controller.dispatch(action, req, res)
50
- end
48
+ def dispatch(controller, action, req, res)
49
+ controller.dispatch(action, req, res)
50
+ end
51
51
  end
52
52
 
53
53
  class StaticDispatcher < Dispatcher
@@ -282,7 +282,7 @@ module ActionDispatch
282
282
 
283
283
  if args.size < path_params_size
284
284
  path_params -= controller_options.keys
285
- path_params -= result.keys
285
+ path_params -= (result[:path_params] || {}).merge(result).keys
286
286
  else
287
287
  path_params = path_params.dup
288
288
  end
@@ -375,6 +375,7 @@ module ActionDispatch
375
375
  @disable_clear_and_finalize = false
376
376
  @finalized = false
377
377
  @env_key = "ROUTES_#{object_id}_SCRIPT_NAME"
378
+ @default_env = nil
378
379
 
379
380
  @set = Journey::Routes.new
380
381
  @router = Journey::Router.new @set
@@ -405,6 +406,25 @@ module ActionDispatch
405
406
  end
406
407
  private :make_request
407
408
 
409
+ def default_env
410
+ if default_url_options != @default_env&.[]("action_dispatch.routes.default_url_options")
411
+ url_options = default_url_options.dup.freeze
412
+ uri = URI(ActionDispatch::Http::URL.full_url_for(host: "example.org", **url_options))
413
+
414
+ @default_env = {
415
+ "action_dispatch.routes" => self,
416
+ "action_dispatch.routes.default_url_options" => url_options,
417
+ "HTTPS" => uri.scheme == "https" ? "on" : "off",
418
+ "rack.url_scheme" => uri.scheme,
419
+ "HTTP_HOST" => uri.port == uri.default_port ? uri.host : "#{uri.host}:#{uri.port}",
420
+ "SCRIPT_NAME" => uri.path.chomp("/"),
421
+ "rack.input" => "",
422
+ }.freeze
423
+ end
424
+
425
+ @default_env
426
+ end
427
+
408
428
  def draw(&block)
409
429
  clear! unless @disable_clear_and_finalize
410
430
  eval_block(block)
@@ -574,6 +594,20 @@ module ActionDispatch
574
594
  end
575
595
 
576
596
  private :_generate_paths_by_default
597
+
598
+ # If the module is included more than once (for example, in a subclass
599
+ # of an ancestor that includes the module), ensure that the `_routes`
600
+ # singleton and instance methods return the desired route set by
601
+ # including a new copy of the module (recursively if necessary). Note
602
+ # that this method is called for each inclusion, whereas the above
603
+ # `included` block is run only for the initial inclusion of each copy.
604
+ def self.included(base)
605
+ super
606
+ if base.respond_to?(:_routes) && !base._routes.equal?(@_proxy._routes)
607
+ @dup_for_reinclude ||= self.dup
608
+ base.include @dup_for_reinclude
609
+ end
610
+ end
577
611
  end
578
612
  end
579
613
 
@@ -596,16 +630,16 @@ module ActionDispatch
596
630
  named_routes[name] = route if name
597
631
 
598
632
  if route.segment_keys.include?(:controller)
599
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
633
+ ActionDispatch.deprecator.warn(<<-MSG.squish)
600
634
  Using a dynamic :controller segment in a route is deprecated and
601
- will be removed in Rails 7.1.
635
+ will be removed in Rails 7.2.
602
636
  MSG
603
637
  end
604
638
 
605
639
  if route.segment_keys.include?(:action)
606
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
640
+ ActionDispatch.deprecator.warn(<<-MSG.squish)
607
641
  Using a dynamic :action segment in a route is deprecated and
608
- will be removed in Rails 7.1.
642
+ will be removed in Rails 7.2.
609
643
  MSG
610
644
  end
611
645
 
@@ -779,18 +813,14 @@ module ActionDispatch
779
813
 
780
814
  RESERVED_OPTIONS = [:host, :protocol, :port, :subdomain, :domain, :tld_length,
781
815
  :trailing_slash, :anchor, :params, :only_path, :script_name,
782
- :original_script_name, :relative_url_root]
816
+ :original_script_name]
783
817
 
784
818
  def optimize_routes_generation?
785
819
  default_url_options.empty?
786
820
  end
787
821
 
788
822
  def find_script_name(options)
789
- options.delete(:script_name) || find_relative_url_root(options) || ""
790
- end
791
-
792
- def find_relative_url_root(options)
793
- options.delete(:relative_url_root) || relative_url_root
823
+ options.delete(:script_name) || relative_url_root || ""
794
824
  end
795
825
 
796
826
  def path_for(options, route_name = nil, reserved = RESERVED_OPTIONS)
@@ -854,7 +884,7 @@ module ActionDispatch
854
884
 
855
885
  def recognize_path(path, environment = {})
856
886
  method = (environment[:method] || "GET").to_s.upcase
857
- path = Journey::Router::Utils.normalize_path(path) unless %r{://}.match?(path)
887
+ path = Journey::Router::Utils.normalize_path(path) unless path&.include?("://")
858
888
  extras = environment[:extras] || {}
859
889
 
860
890
  begin
@@ -873,7 +903,7 @@ module ActionDispatch
873
903
  params.each do |key, value|
874
904
  if value.is_a?(String)
875
905
  value = value.dup.force_encoding(Encoding::BINARY)
876
- params[key] = URI::DEFAULT_PARSER.unescape(value)
906
+ params[key] = RFC2396_PARSER.unescape(value)
877
907
  end
878
908
  end
879
909
  req.path_parameters = params
@@ -29,23 +29,18 @@ module ActionDispatch
29
29
 
30
30
  def method_missing(method, *args)
31
31
  if @helpers.respond_to?(method)
32
- self.class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
33
- def #{method}(*args)
34
- options = args.extract_options!
35
- options = url_options.merge((options || {}).symbolize_keys)
32
+ options = args.extract_options!
33
+ options = url_options.merge((options || {}).symbolize_keys)
36
34
 
37
- if @script_namer
38
- options[:script_name] = merge_script_names(
39
- options[:script_name],
40
- @script_namer.call(options)
41
- )
42
- end
35
+ if @script_namer
36
+ options[:script_name] = merge_script_names(
37
+ options[:script_name],
38
+ @script_namer.call(options)
39
+ )
40
+ end
43
41
 
44
- args << options
45
- @helpers.#{method}(*args)
46
- end
47
- RUBY
48
- public_send(method, *args)
42
+ args << options
43
+ @helpers.public_send(method, *args)
49
44
  else
50
45
  super
51
46
  end
@@ -2,20 +2,22 @@
2
2
 
3
3
  module ActionDispatch
4
4
  module Routing
5
+ # = Action Dispatch Routing \UrlFor
6
+ #
5
7
  # In <tt>config/routes.rb</tt> you define URL-to-controller mappings, but the reverse
6
8
  # is also possible: a URL can be generated from one of your routing definitions.
7
9
  # URL generation functionality is centralized in this module.
8
10
  #
9
- # See ActionDispatch::Routing for general information about routing and routes.rb.
11
+ # See ActionDispatch::Routing for general information about routing and <tt>config/routes.rb</tt>.
10
12
  #
11
13
  # <b>Tip:</b> If you need to generate URLs from your models or some other place,
12
- # then ActionController::UrlFor is what you're looking for. Read on for
14
+ # then ActionDispatch::Routing::UrlFor is what you're looking for. Read on for
13
15
  # an introduction. In general, this module should not be included on its own,
14
- # as it is usually included by url_helpers (as in Rails.application.routes.url_helpers).
16
+ # as it is usually included by +url_helpers+ (as in <tt>Rails.application.routes.url_helpers</tt>).
15
17
  #
16
18
  # == URL generation from parameters
17
19
  #
18
- # As you may know, some functions, such as ActionController::Base#url_for
20
+ # As you may know, some functions, such as <tt>ActionController::Base#url_for</tt>
19
21
  # and ActionView::Helpers::UrlHelper#link_to, can generate URLs given a set
20
22
  # of parameters. For example, you've probably had the chance to write code
21
23
  # like this in one of your views:
@@ -24,12 +26,12 @@ module ActionDispatch
24
26
  # action: 'new', message: 'Welcome!') %>
25
27
  # # => <a href="/users/new?message=Welcome%21">Click here</a>
26
28
  #
27
- # link_to, and all other functions that require URL generation functionality,
28
- # actually use ActionController::UrlFor under the hood. And in particular,
29
- # they use the ActionController::UrlFor#url_for method. One can generate
29
+ # +link_to+, and all other functions that require URL generation functionality,
30
+ # actually use ActionDispatch::Routing::UrlFor under the hood. And in particular,
31
+ # they use the ActionDispatch::Routing::UrlFor#url_for method. One can generate
30
32
  # the same path as the above example by using the following code:
31
33
  #
32
- # include UrlFor
34
+ # include ActionDispatch::Routing::UrlFor
33
35
  # url_for(controller: 'users',
34
36
  # action: 'new',
35
37
  # message: 'Welcome!',
@@ -37,7 +39,7 @@ module ActionDispatch
37
39
  # # => "/users/new?message=Welcome%21"
38
40
  #
39
41
  # Notice the <tt>only_path: true</tt> part. This is because UrlFor has no
40
- # information about the website hostname that your Rails app is serving. So if you
42
+ # information about the website hostname that your \Rails app is serving. So if you
41
43
  # want to include the hostname as well, then you must also pass the <tt>:host</tt>
42
44
  # argument:
43
45
  #
@@ -48,17 +50,17 @@ module ActionDispatch
48
50
  # host: 'www.example.com')
49
51
  # # => "http://www.example.com/users/new?message=Welcome%21"
50
52
  #
51
- # By default, all controllers and views have access to a special version of url_for,
52
- # that already knows what the current hostname is. So if you use url_for in your
53
+ # By default, all controllers and views have access to a special version of +url_for+,
54
+ # that already knows what the current hostname is. So if you use +url_for+ in your
53
55
  # controllers or your views, then you don't need to explicitly pass the <tt>:host</tt>
54
56
  # argument.
55
57
  #
56
- # For convenience reasons, mailers provide a shortcut for ActionController::UrlFor#url_for.
57
- # So within mailers, you only have to type +url_for+ instead of 'ActionController::UrlFor#url_for'
58
- # in full. However, mailers don't have hostname information, and you still have to provide
59
- # the +:host+ argument or set the default host that will be used in all mailers using the
60
- # configuration option +config.action_mailer.default_url_options+. For more information on
61
- # url_for in mailers read the ActionMailer#Base documentation.
58
+ # For convenience, mailers also include ActionDispatch::Routing::UrlFor. So
59
+ # within mailers, you can use url_for. However, mailers cannot access
60
+ # incoming web requests in order to derive hostname information, so you have
61
+ # to provide the +:host+ option or set the default host using
62
+ # +default_url_options+. For more information on url_for in mailers see the
63
+ # ActionMailer::Base documentation.
62
64
  #
63
65
  #
64
66
  # == URL generation for named routes
@@ -72,7 +74,7 @@ module ActionDispatch
72
74
  # This generates, among other things, the method <tt>users_path</tt>. By default,
73
75
  # this method is accessible from your controllers, views, and mailers. If you need
74
76
  # to access this auto-generated method from other places (such as a model), then
75
- # you can do that by including Rails.application.routes.url_helpers in your class:
77
+ # you can do that by including <tt>Rails.application.routes.url_helpers</tt> in your class:
76
78
  #
77
79
  # class User < ActiveRecord::Base
78
80
  # include Rails.application.routes.url_helpers
@@ -115,11 +117,11 @@ module ActionDispatch
115
117
  default_url_options
116
118
  end
117
119
 
118
- # Generate a URL based on the options provided, default_url_options, and the
119
- # routes defined in routes.rb. The following options are supported:
120
+ # Generate a URL based on the options provided, +default_url_options+, and the
121
+ # routes defined in <tt>config/routes.rb</tt>. The following options are supported:
120
122
  #
121
123
  # * <tt>:only_path</tt> - If true, the relative URL is returned. Defaults to +false+.
122
- # * <tt>:protocol</tt> - The protocol to connect to. Defaults to 'http'.
124
+ # * <tt>:protocol</tt> - The protocol to connect to. Defaults to <tt>"http"</tt>.
123
125
  # * <tt>:host</tt> - Specifies the host the link should be targeted at.
124
126
  # If <tt>:only_path</tt> is false, this option must be
125
127
  # provided either explicitly, or via +default_url_options+.
@@ -134,7 +136,9 @@ module ActionDispatch
134
136
  # * <tt>:port</tt> - Optionally specify the port to connect to.
135
137
  # * <tt>:anchor</tt> - An anchor name to be appended to the path.
136
138
  # * <tt>:params</tt> - The query parameters to be appended to the path.
137
- # * <tt>:trailing_slash</tt> - If true, adds a trailing slash, as in "/archive/2009/"
139
+ # * <tt>:path_params</tt> - The query parameters that will only be used
140
+ # for the named dynamic segments of path. If unused, they will be discarded.
141
+ # * <tt>:trailing_slash</tt> - If true, adds a trailing slash, as in <tt>"/archive/2009/"</tt>.
138
142
  # * <tt>:script_name</tt> - Specifies application path relative to domain root. If provided, prepends application path.
139
143
  #
140
144
  # Any other key (<tt>:controller</tt>, <tt>:action</tt>, etc.) given to
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/string/filters"
4
-
5
3
  module ActionDispatch
6
4
  # The routing module provides URL rewriting in native Ruby. It's a way to
7
5
  # redirect incoming requests to controllers and actions. This replaces
@@ -119,9 +117,9 @@ module ActionDispatch
119
117
  #
120
118
  # # In config/routes.rb
121
119
  # controller :blog do
122
- # get 'blog/show', to: :list
123
- # get 'blog/delete', to: :delete
124
- # get 'blog/edit', to: :edit
120
+ # get 'blog/show' => :list
121
+ # get 'blog/delete' => :delete
122
+ # get 'blog/edit' => :edit
125
123
  # end
126
124
  #
127
125
  # # provides named routes for show, delete, and edit
@@ -240,7 +238,7 @@ module ActionDispatch
240
238
  #
241
239
  # == View a list of all your routes
242
240
  #
243
- # rails routes
241
+ # $ bin/rails routes
244
242
  #
245
243
  # Target a specific controller with <tt>-c</tt>, or grep routes
246
244
  # using <tt>-g</tt>. Useful in conjunction with <tt>--expanded</tt>
@@ -250,7 +248,9 @@ module ActionDispatch
250
248
 
251
249
  autoload :Mapper
252
250
  autoload :RouteSet
253
- autoload :RoutesProxy
251
+ eager_autoload do
252
+ autoload :RoutesProxy
253
+ end
254
254
  autoload :UrlFor
255
255
  autoload :PolymorphicRoutes
256
256