actionpack 7.1.5.1 → 8.1.2

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 (177) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +308 -523
  3. data/README.rdoc +1 -1
  4. data/lib/abstract_controller/asset_paths.rb +6 -2
  5. data/lib/abstract_controller/base.rb +104 -105
  6. data/lib/abstract_controller/caching/fragments.rb +50 -53
  7. data/lib/abstract_controller/caching.rb +8 -3
  8. data/lib/abstract_controller/callbacks.rb +70 -62
  9. data/lib/abstract_controller/collector.rb +7 -7
  10. data/lib/abstract_controller/deprecator.rb +2 -0
  11. data/lib/abstract_controller/error.rb +2 -0
  12. data/lib/abstract_controller/helpers.rb +71 -84
  13. data/lib/abstract_controller/logger.rb +4 -1
  14. data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
  15. data/lib/abstract_controller/rendering.rb +13 -13
  16. data/lib/abstract_controller/translation.rb +12 -13
  17. data/lib/abstract_controller/url_for.rb +8 -6
  18. data/lib/abstract_controller.rb +2 -0
  19. data/lib/action_controller/api/api_rendering.rb +2 -0
  20. data/lib/action_controller/api.rb +76 -72
  21. data/lib/action_controller/base.rb +199 -126
  22. data/lib/action_controller/caching.rb +16 -14
  23. data/lib/action_controller/deprecator.rb +2 -0
  24. data/lib/action_controller/form_builder.rb +21 -18
  25. data/lib/action_controller/log_subscriber.rb +23 -2
  26. data/lib/action_controller/metal/allow_browser.rb +133 -0
  27. data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
  28. data/lib/action_controller/metal/conditional_get.rb +217 -175
  29. data/lib/action_controller/metal/content_security_policy.rb +25 -24
  30. data/lib/action_controller/metal/cookies.rb +4 -2
  31. data/lib/action_controller/metal/data_streaming.rb +72 -63
  32. data/lib/action_controller/metal/default_headers.rb +5 -3
  33. data/lib/action_controller/metal/etag_with_flash.rb +3 -1
  34. data/lib/action_controller/metal/etag_with_template_digest.rb +17 -15
  35. data/lib/action_controller/metal/exceptions.rb +16 -9
  36. data/lib/action_controller/metal/flash.rb +13 -14
  37. data/lib/action_controller/metal/head.rb +15 -11
  38. data/lib/action_controller/metal/helpers.rb +63 -55
  39. data/lib/action_controller/metal/http_authentication.rb +209 -201
  40. data/lib/action_controller/metal/implicit_render.rb +17 -15
  41. data/lib/action_controller/metal/instrumentation.rb +16 -14
  42. data/lib/action_controller/metal/live.rb +177 -128
  43. data/lib/action_controller/metal/logging.rb +6 -4
  44. data/lib/action_controller/metal/mime_responds.rb +151 -142
  45. data/lib/action_controller/metal/parameter_encoding.rb +34 -32
  46. data/lib/action_controller/metal/params_wrapper.rb +57 -59
  47. data/lib/action_controller/metal/permissions_policy.rb +22 -12
  48. data/lib/action_controller/metal/rate_limiting.rb +92 -0
  49. data/lib/action_controller/metal/redirecting.rb +213 -94
  50. data/lib/action_controller/metal/renderers.rb +78 -57
  51. data/lib/action_controller/metal/rendering.rb +111 -77
  52. data/lib/action_controller/metal/request_forgery_protection.rb +182 -143
  53. data/lib/action_controller/metal/rescue.rb +20 -9
  54. data/lib/action_controller/metal/streaming.rb +118 -195
  55. data/lib/action_controller/metal/strong_parameters.rb +720 -530
  56. data/lib/action_controller/metal/testing.rb +2 -0
  57. data/lib/action_controller/metal/url_for.rb +17 -15
  58. data/lib/action_controller/metal.rb +86 -60
  59. data/lib/action_controller/railtie.rb +36 -15
  60. data/lib/action_controller/railties/helpers.rb +2 -0
  61. data/lib/action_controller/renderer.rb +41 -36
  62. data/lib/action_controller/structured_event_subscriber.rb +116 -0
  63. data/lib/action_controller/template_assertions.rb +4 -2
  64. data/lib/action_controller/test_case.rb +160 -131
  65. data/lib/action_controller.rb +5 -1
  66. data/lib/action_dispatch/constants.rb +8 -0
  67. data/lib/action_dispatch/deprecator.rb +2 -0
  68. data/lib/action_dispatch/http/cache.rb +163 -35
  69. data/lib/action_dispatch/http/content_disposition.rb +2 -0
  70. data/lib/action_dispatch/http/content_security_policy.rb +54 -39
  71. data/lib/action_dispatch/http/filter_parameters.rb +14 -8
  72. data/lib/action_dispatch/http/filter_redirect.rb +22 -1
  73. data/lib/action_dispatch/http/headers.rb +22 -22
  74. data/lib/action_dispatch/http/mime_negotiation.rb +89 -41
  75. data/lib/action_dispatch/http/mime_type.rb +25 -21
  76. data/lib/action_dispatch/http/mime_types.rb +3 -0
  77. data/lib/action_dispatch/http/param_builder.rb +187 -0
  78. data/lib/action_dispatch/http/param_error.rb +26 -0
  79. data/lib/action_dispatch/http/parameters.rb +14 -12
  80. data/lib/action_dispatch/http/permissions_policy.rb +25 -36
  81. data/lib/action_dispatch/http/query_parser.rb +55 -0
  82. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  83. data/lib/action_dispatch/http/request.rb +141 -92
  84. data/lib/action_dispatch/http/response.rb +137 -77
  85. data/lib/action_dispatch/http/upload.rb +18 -16
  86. data/lib/action_dispatch/http/url.rb +187 -89
  87. data/lib/action_dispatch/journey/formatter.rb +21 -9
  88. data/lib/action_dispatch/journey/gtg/builder.rb +4 -3
  89. data/lib/action_dispatch/journey/gtg/simulator.rb +34 -11
  90. data/lib/action_dispatch/journey/gtg/transition_table.rb +47 -53
  91. data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
  92. data/lib/action_dispatch/journey/nodes/node.rb +8 -6
  93. data/lib/action_dispatch/journey/parser.rb +99 -195
  94. data/lib/action_dispatch/journey/path/pattern.rb +4 -1
  95. data/lib/action_dispatch/journey/route.rb +54 -38
  96. data/lib/action_dispatch/journey/router/utils.rb +22 -27
  97. data/lib/action_dispatch/journey/router.rb +63 -83
  98. data/lib/action_dispatch/journey/routes.rb +11 -2
  99. data/lib/action_dispatch/journey/scanner.rb +46 -42
  100. data/lib/action_dispatch/journey/visitors.rb +57 -23
  101. data/lib/action_dispatch/journey/visualizer/fsm.js +4 -6
  102. data/lib/action_dispatch/journey.rb +2 -0
  103. data/lib/action_dispatch/log_subscriber.rb +7 -1
  104. data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -0
  105. data/lib/action_dispatch/middleware/assume_ssl.rb +8 -5
  106. data/lib/action_dispatch/middleware/callbacks.rb +3 -1
  107. data/lib/action_dispatch/middleware/cookies.rb +125 -106
  108. data/lib/action_dispatch/middleware/debug_exceptions.rb +37 -8
  109. data/lib/action_dispatch/middleware/debug_locks.rb +15 -13
  110. data/lib/action_dispatch/middleware/debug_view.rb +13 -5
  111. data/lib/action_dispatch/middleware/exception_wrapper.rb +18 -23
  112. data/lib/action_dispatch/middleware/executor.rb +19 -4
  113. data/lib/action_dispatch/middleware/flash.rb +63 -51
  114. data/lib/action_dispatch/middleware/host_authorization.rb +17 -15
  115. data/lib/action_dispatch/middleware/public_exceptions.rb +14 -12
  116. data/lib/action_dispatch/middleware/reloader.rb +5 -3
  117. data/lib/action_dispatch/middleware/remote_ip.rb +87 -77
  118. data/lib/action_dispatch/middleware/request_id.rb +16 -10
  119. data/lib/action_dispatch/middleware/server_timing.rb +4 -2
  120. data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -0
  121. data/lib/action_dispatch/middleware/session/cache_store.rb +30 -8
  122. data/lib/action_dispatch/middleware/session/cookie_store.rb +27 -26
  123. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -3
  124. data/lib/action_dispatch/middleware/show_exceptions.rb +16 -16
  125. data/lib/action_dispatch/middleware/ssl.rb +53 -40
  126. data/lib/action_dispatch/middleware/stack.rb +11 -10
  127. data/lib/action_dispatch/middleware/static.rb +33 -31
  128. data/lib/action_dispatch/middleware/templates/rescues/_copy_button.html.erb +1 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +3 -5
  130. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +9 -5
  131. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +1 -0
  132. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +1 -0
  133. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +50 -0
  136. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -0
  137. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -0
  138. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -0
  139. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -0
  140. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -0
  141. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +1 -1
  142. data/lib/action_dispatch/railtie.rb +23 -3
  143. data/lib/action_dispatch/request/session.rb +24 -21
  144. data/lib/action_dispatch/request/utils.rb +11 -3
  145. data/lib/action_dispatch/routing/endpoint.rb +2 -0
  146. data/lib/action_dispatch/routing/inspector.rb +85 -60
  147. data/lib/action_dispatch/routing/mapper.rb +1031 -851
  148. data/lib/action_dispatch/routing/polymorphic_routes.rb +69 -62
  149. data/lib/action_dispatch/routing/redirection.rb +47 -39
  150. data/lib/action_dispatch/routing/route_set.rb +79 -56
  151. data/lib/action_dispatch/routing/routes_proxy.rb +7 -4
  152. data/lib/action_dispatch/routing/url_for.rb +130 -125
  153. data/lib/action_dispatch/routing.rb +150 -148
  154. data/lib/action_dispatch/structured_event_subscriber.rb +20 -0
  155. data/lib/action_dispatch/system_test_case.rb +91 -81
  156. data/lib/action_dispatch/system_testing/browser.rb +16 -23
  157. data/lib/action_dispatch/system_testing/driver.rb +2 -0
  158. data/lib/action_dispatch/system_testing/server.rb +2 -0
  159. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +34 -23
  160. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
  161. data/lib/action_dispatch/testing/assertion_response.rb +9 -7
  162. data/lib/action_dispatch/testing/assertions/response.rb +52 -25
  163. data/lib/action_dispatch/testing/assertions/routing.rb +168 -87
  164. data/lib/action_dispatch/testing/assertions.rb +2 -0
  165. data/lib/action_dispatch/testing/integration.rb +233 -223
  166. data/lib/action_dispatch/testing/request_encoder.rb +11 -9
  167. data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
  168. data/lib/action_dispatch/testing/test_process.rb +11 -8
  169. data/lib/action_dispatch/testing/test_request.rb +3 -1
  170. data/lib/action_dispatch/testing/test_response.rb +27 -26
  171. data/lib/action_dispatch.rb +36 -32
  172. data/lib/action_pack/gem_version.rb +6 -4
  173. data/lib/action_pack/version.rb +3 -1
  174. data/lib/action_pack.rb +17 -16
  175. metadata +36 -32
  176. data/lib/action_dispatch/journey/parser.y +0 -50
  177. data/lib/action_dispatch/journey/parser_extras.rb +0 -31
@@ -1,104 +1,111 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionDispatch
4
6
  module Routing
5
- # = Action Dispatch Routing \PolymorphicRoutes
7
+ # # Action Dispatch Routing PolymorphicRoutes
6
8
  #
7
- # Polymorphic URL helpers are methods for smart resolution to a named route call when
8
- # given an Active Record model instance. They are to be used in combination with
9
- # ActionController::Resources.
9
+ # Polymorphic URL helpers are methods for smart resolution to a named route call
10
+ # when given an Active Record model instance. They are to be used in combination
11
+ # with ActionController::Resources.
10
12
  #
11
- # These methods are useful when you want to generate the correct URL or path to a RESTful
12
- # resource without having to know the exact type of the record in question.
13
+ # These methods are useful when you want to generate the correct URL or path to
14
+ # a RESTful resource without having to know the exact type of the record in
15
+ # question.
13
16
  #
14
- # Nested resources and/or namespaces are also supported, as illustrated in the example:
17
+ # Nested resources and/or namespaces are also supported, as illustrated in the
18
+ # example:
15
19
  #
16
- # polymorphic_url([:admin, @article, @comment])
20
+ # polymorphic_url([:admin, @article, @comment])
17
21
  #
18
22
  # results in:
19
23
  #
20
- # admin_article_comment_url(@article, @comment)
24
+ # admin_article_comment_url(@article, @comment)
25
+ #
26
+ # ## Usage within the framework
21
27
  #
22
- # == Usage within the framework
28
+ # Polymorphic URL helpers are used in a number of places throughout the Rails
29
+ # framework:
23
30
  #
24
- # Polymorphic URL helpers are used in a number of places throughout the \Rails framework:
31
+ # * `url_for`, so you can use it with a record as the argument, e.g.
32
+ # `url_for(@article)`;
33
+ # * ActionView::Helpers::FormHelper uses `polymorphic_path`, so you can write
34
+ # `form_with(model: @article)` without having to specify `:url` parameter for the
35
+ # form action;
36
+ # * `redirect_to` (which, in fact, uses `url_for`) so you can write
37
+ # `redirect_to(post)` in your controllers;
38
+ # * ActionView::Helpers::AtomFeedHelper, so you don't have to explicitly
39
+ # specify URLs for feed entries.
25
40
  #
26
- # * <tt>url_for</tt>, so you can use it with a record as the argument, e.g.
27
- # <tt>url_for(@article)</tt>;
28
- # * ActionView::Helpers::FormHelper uses <tt>polymorphic_path</tt>, so you can write
29
- # <tt>form_for(@article)</tt> without having to specify <tt>:url</tt> parameter for the form
30
- # action;
31
- # * <tt>redirect_to</tt> (which, in fact, uses <tt>url_for</tt>) so you can write
32
- # <tt>redirect_to(post)</tt> in your controllers;
33
- # * ActionView::Helpers::AtomFeedHelper, so you don't have to explicitly specify URLs
34
- # for feed entries.
35
41
  #
36
- # == Prefixed polymorphic helpers
42
+ # ## Prefixed polymorphic helpers
37
43
  #
38
- # In addition to <tt>polymorphic_url</tt> and <tt>polymorphic_path</tt> methods, a
39
- # number of prefixed helpers are available as a shorthand to <tt>action: "..."</tt>
40
- # in options. Those are:
44
+ # In addition to `polymorphic_url` and `polymorphic_path` methods, a number of
45
+ # prefixed helpers are available as a shorthand to `action: "..."` in options.
46
+ # Those are:
47
+ #
48
+ # * `edit_polymorphic_url`, `edit_polymorphic_path`
49
+ # * `new_polymorphic_url`, `new_polymorphic_path`
41
50
  #
42
- # * <tt>edit_polymorphic_url</tt>, <tt>edit_polymorphic_path</tt>
43
- # * <tt>new_polymorphic_url</tt>, <tt>new_polymorphic_path</tt>
44
51
  #
45
52
  # Example usage:
46
53
  #
47
- # edit_polymorphic_path(@post) # => "/posts/1/edit"
48
- # polymorphic_path(@post, format: :pdf) # => "/posts/1.pdf"
54
+ # edit_polymorphic_path(@post) # => "/posts/1/edit"
55
+ # polymorphic_path(@post, format: :pdf) # => "/posts/1.pdf"
49
56
  #
50
- # == Usage with mounted engines
57
+ # ## Usage with mounted engines
51
58
  #
52
59
  # If you are using a mounted engine and you need to use a polymorphic_url
53
60
  # pointing at the engine's routes, pass in the engine's route proxy as the first
54
61
  # argument to the method. For example:
55
62
  #
56
- # polymorphic_url([blog, @post]) # calls blog.post_path(@post)
57
- # form_for([blog, @post]) # => "/blog/posts/1"
63
+ # polymorphic_url([blog, @post]) # calls blog.post_path(@post)
64
+ # form_with(model: [blog, @post]) # => "/blog/posts/1"
58
65
  #
59
66
  module PolymorphicRoutes
60
- # Constructs a call to a named RESTful route for the given record and returns the
61
- # resulting URL string. For example:
67
+ # Constructs a call to a named RESTful route for the given record and returns
68
+ # the resulting URL string. For example:
69
+ #
70
+ # # calls post_url(post)
71
+ # polymorphic_url(post) # => "http://example.com/posts/1"
72
+ # polymorphic_url([blog, post]) # => "http://example.com/blogs/1/posts/1"
73
+ # polymorphic_url([:admin, blog, post]) # => "http://example.com/admin/blogs/1/posts/1"
74
+ # polymorphic_url([user, :blog, post]) # => "http://example.com/users/1/blog/posts/1"
75
+ # polymorphic_url(Comment) # => "http://example.com/comments"
62
76
  #
63
- # # calls post_url(post)
64
- # polymorphic_url(post) # => "http://example.com/posts/1"
65
- # polymorphic_url([blog, post]) # => "http://example.com/blogs/1/posts/1"
66
- # polymorphic_url([:admin, blog, post]) # => "http://example.com/admin/blogs/1/posts/1"
67
- # polymorphic_url([user, :blog, post]) # => "http://example.com/users/1/blog/posts/1"
68
- # polymorphic_url(Comment) # => "http://example.com/comments"
77
+ # #### Options
69
78
  #
70
- # ==== Options
79
+ # * `:action` - Specifies the action prefix for the named route: `:new` or
80
+ # `:edit`. Default is no prefix.
81
+ # * `:routing_type` - Allowed values are `:path` or `:url`. Default is `:url`.
71
82
  #
72
- # * <tt>:action</tt> - Specifies the action prefix for the named route:
73
- # <tt>:new</tt> or <tt>:edit</tt>. Default is no prefix.
74
- # * <tt>:routing_type</tt> - Allowed values are <tt>:path</tt> or <tt>:url</tt>.
75
- # Default is <tt>:url</tt>.
76
83
  #
77
- # Also includes all the options from <tt>url_for</tt>. These include such
78
- # things as <tt>:anchor</tt> or <tt>:trailing_slash</tt>. Example usage
79
- # is given below:
84
+ # Also includes all the options from `url_for`. These include such things as
85
+ # `:anchor` or `:trailing_slash`. Example usage is given below:
80
86
  #
81
- # polymorphic_url([blog, post], anchor: 'my_anchor')
82
- # # => "http://example.com/blogs/1/posts/1#my_anchor"
83
- # polymorphic_url([blog, post], anchor: 'my_anchor', script_name: "/my_app")
84
- # # => "http://example.com/my_app/blogs/1/posts/1#my_anchor"
87
+ # polymorphic_url([blog, post], anchor: 'my_anchor')
88
+ # # => "http://example.com/blogs/1/posts/1#my_anchor"
89
+ # polymorphic_url([blog, post], anchor: 'my_anchor', script_name: "/my_app")
90
+ # # => "http://example.com/my_app/blogs/1/posts/1#my_anchor"
85
91
  #
86
- # For all of these options, see the documentation for {url_for}[rdoc-ref:ActionDispatch::Routing::UrlFor].
92
+ # For all of these options, see the documentation for
93
+ # [url_for](rdoc-ref:ActionDispatch::Routing::UrlFor).
87
94
  #
88
- # ==== Functionality
95
+ # #### Functionality
89
96
  #
90
- # # an Article record
91
- # polymorphic_url(record) # same as article_url(record)
97
+ # # an Article record
98
+ # polymorphic_url(record) # same as article_url(record)
92
99
  #
93
- # # a Comment record
94
- # polymorphic_url(record) # same as comment_url(record)
100
+ # # a Comment record
101
+ # polymorphic_url(record) # same as comment_url(record)
95
102
  #
96
- # # it recognizes new records and maps to the collection
97
- # record = Comment.new
98
- # polymorphic_url(record) # same as comments_url()
103
+ # # it recognizes new records and maps to the collection
104
+ # record = Comment.new
105
+ # polymorphic_url(record) # same as comments_url()
99
106
  #
100
- # # the class of a record will also map to the collection
101
- # polymorphic_url(Comment) # same as comments_url()
107
+ # # the class of a record will also map to the collection
108
+ # polymorphic_url(Comment) # same as comments_url()
102
109
  #
103
110
  def polymorphic_url(record_or_hash_or_array, options = {})
104
111
  if Hash === record_or_hash_or_array
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "active_support/core_ext/array/extract_options"
4
6
  require "rack/utils"
5
7
  require "action_controller/metal/exceptions"
@@ -10,9 +12,10 @@ module ActionDispatch
10
12
  class Redirect < Endpoint # :nodoc:
11
13
  attr_reader :status, :block
12
14
 
13
- def initialize(status, block)
15
+ def initialize(status, block, source_location)
14
16
  @status = status
15
17
  @block = block
18
+ @source_location = source_location
16
19
  end
17
20
 
18
21
  def redirect?; true; end
@@ -25,6 +28,7 @@ module ActionDispatch
25
28
  payload[:status] = @status
26
29
  payload[:location] = response.headers["Location"]
27
30
  payload[:request] = request
31
+ payload[:source_location] = @source_location if @source_location
28
32
 
29
33
  response.to_a
30
34
  end
@@ -146,67 +150,71 @@ module ActionDispatch
146
150
  module Redirection
147
151
  # Redirect any path to another path:
148
152
  #
149
- # get "/stories" => redirect("/posts")
153
+ # get "/stories" => redirect("/posts")
150
154
  #
151
- # This will redirect the user, while ignoring certain parts of the request, including query string, etc.
152
- # <tt>/stories</tt>, <tt>/stories?foo=bar</tt>, etc all redirect to <tt>/posts</tt>.
155
+ # This will redirect the user, while ignoring certain parts of the request,
156
+ # including query string, etc. `/stories`, `/stories?foo=bar`, etc all redirect
157
+ # to `/posts`.
153
158
  #
154
- # The redirect will use a <tt>301 Moved Permanently</tt> status code by
155
- # default. This can be overridden with the +:status+ option:
159
+ # The redirect will use a `301 Moved Permanently` status code by default. This
160
+ # can be overridden with the `:status` option:
156
161
  #
157
- # get "/stories" => redirect("/posts", status: 307)
162
+ # get "/stories" => redirect("/posts", status: 307)
158
163
  #
159
164
  # You can also use interpolation in the supplied redirect argument:
160
165
  #
161
- # get 'docs/:article', to: redirect('/wiki/%{article}')
166
+ # get 'docs/:article', to: redirect('/wiki/%{article}')
162
167
  #
163
- # Note that if you return a path without a leading slash then the URL is prefixed with the
164
- # current SCRIPT_NAME environment variable. This is typically '/' but may be different in
165
- # a mounted engine or where the application is deployed to a subdirectory of a website.
168
+ # Note that if you return a path without a leading slash then the URL is
169
+ # prefixed with the current SCRIPT_NAME environment variable. This is typically
170
+ # '/' but may be different in a mounted engine or where the application is
171
+ # deployed to a subdirectory of a website.
166
172
  #
167
173
  # Alternatively you can use one of the other syntaxes:
168
174
  #
169
- # The block version of redirect allows for the easy encapsulation of any logic associated with
170
- # the redirect in question. Either the params and request are supplied as arguments, or just
171
- # params, depending of how many arguments your block accepts. A string is required as a
172
- # return value.
175
+ # The block version of redirect allows for the easy encapsulation of any logic
176
+ # associated with the redirect in question. Either the params and request are
177
+ # supplied as arguments, or just params, depending of how many arguments your
178
+ # block accepts. A string is required as a return value.
173
179
  #
174
- # get 'jokes/:number', to: redirect { |params, request|
175
- # path = (params[:number].to_i.even? ? "wheres-the-beef" : "i-love-lamp")
176
- # "http://#{request.host_with_port}/#{path}"
177
- # }
180
+ # get 'jokes/:number', to: redirect { |params, request|
181
+ # path = (params[:number].to_i.even? ? "wheres-the-beef" : "i-love-lamp")
182
+ # "http://#{request.host_with_port}/#{path}"
183
+ # }
178
184
  #
179
- # Note that the <tt>do end</tt> syntax for the redirect block wouldn't work, as Ruby would pass
180
- # the block to +get+ instead of +redirect+. Use <tt>{ ... }</tt> instead.
185
+ # Note that the `do end` syntax for the redirect block wouldn't work, as Ruby
186
+ # would pass the block to `get` instead of `redirect`. Use `{ ... }` instead.
181
187
  #
182
- # The options version of redirect allows you to supply only the parts of the URL which need
183
- # to change, it also supports interpolation of the path similar to the first example.
188
+ # The options version of redirect allows you to supply only the parts of the URL
189
+ # which need to change, it also supports interpolation of the path similar to
190
+ # the first example.
184
191
  #
185
- # get 'stores/:name', to: redirect(subdomain: 'stores', path: '/%{name}')
186
- # get 'stores/:name(*all)', to: redirect(subdomain: 'stores', path: '/%{name}%{all}')
187
- # get '/stories', to: redirect(path: '/posts')
192
+ # get 'stores/:name', to: redirect(subdomain: 'stores', path: '/%{name}')
193
+ # get 'stores/:name(*all)', to: redirect(subdomain: 'stores', path: '/%{name}%{all}')
194
+ # get '/stories', to: redirect(path: '/posts')
188
195
  #
189
- # This will redirect the user, while changing only the specified parts of the request,
190
- # for example the +path+ option in the last example.
191
- # <tt>/stories</tt>, <tt>/stories?foo=bar</tt>, redirect to <tt>/posts</tt> and <tt>/posts?foo=bar</tt> respectively.
196
+ # This will redirect the user, while changing only the specified parts of the
197
+ # request, for example the `path` option in the last example. `/stories`,
198
+ # `/stories?foo=bar`, redirect to `/posts` and `/posts?foo=bar` respectively.
192
199
  #
193
- # Finally, an object which responds to call can be supplied to redirect, allowing you to reuse
194
- # common redirect routes. The call method must accept two arguments, params and request, and return
195
- # a string.
200
+ # Finally, an object which responds to call can be supplied to redirect,
201
+ # allowing you to reuse common redirect routes. The call method must accept two
202
+ # arguments, params and request, and return a string.
196
203
  #
197
- # get 'accounts/:name' => redirect(SubdomainRedirector.new('api'))
204
+ # get 'accounts/:name' => redirect(SubdomainRedirector.new('api'))
198
205
  #
199
206
  def redirect(*args, &block)
200
- options = args.extract_options!
201
- status = options.delete(:status) || 301
202
- path = args.shift
207
+ options = args.extract_options!
208
+ status = options.delete(:status) || 301
209
+ path = args.shift
210
+ source_location = caller[0] if ActionDispatch.verbose_redirect_logs
203
211
 
204
- return OptionRedirect.new(status, options) if options.any?
205
- return PathRedirect.new(status, path) if String === path
212
+ return OptionRedirect.new(status, options, source_location) if options.any?
213
+ return PathRedirect.new(status, path, source_location) if String === path
206
214
 
207
215
  block = path if path.respond_to? :call
208
216
  raise ArgumentError, "redirection argument not supported" unless block
209
- Redirect.new status, block
217
+ Redirect.new status, block, source_location
210
218
  end
211
219
  end
212
220
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "action_dispatch/journey"
4
6
  require "active_support/core_ext/object/to_query"
5
7
  require "active_support/core_ext/module/redefine_method"
@@ -10,12 +12,28 @@ require "action_dispatch/routing/endpoint"
10
12
 
11
13
  module ActionDispatch
12
14
  module Routing
13
- # :stopdoc:
15
+ # The RouteSet contains a collection of Route instances, representing the routes
16
+ # typically defined in `config/routes.rb`.
14
17
  class RouteSet
15
- # Since the router holds references to many parts of the system
16
- # like engines, controllers and the application itself, inspecting
17
- # the route set can actually be really slow, therefore we default
18
- # alias inspect to to_s.
18
+ # Returns a Route matching the given requirements, or `nil` if none are found.
19
+ #
20
+ # This is intended for use by tools such as Language Servers.
21
+ #
22
+ # Given the routes are defined as:
23
+ #
24
+ # resources :posts
25
+ #
26
+ # Then the following will return the Route for the `show` action:
27
+ #
28
+ # Rails.application.routes.from_requirements(controller: "posts", action: "show")
29
+ def from_requirements(requirements)
30
+ routes.find { |route| route.requirements == requirements }
31
+ end
32
+ # :enddoc:
33
+
34
+ # Since the router holds references to many parts of the system like engines,
35
+ # controllers and the application itself, inspecting the route set can actually
36
+ # be really slow, therefore we default alias inspect to to_s.
19
37
  alias inspect to_s
20
38
 
21
39
  class Dispatcher < Routing::Endpoint
@@ -41,8 +59,6 @@ module ActionDispatch
41
59
  private
42
60
  def controller(req)
43
61
  req.controller_class
44
- rescue NameError => e
45
- raise ActionController::RoutingError, e.message, e.backtrace
46
62
  end
47
63
 
48
64
  def dispatch(controller, action, req, res)
@@ -144,8 +160,8 @@ module ActionDispatch
144
160
  routes.length
145
161
  end
146
162
 
147
- # Given a +name+, defines name_path and name_url helpers.
148
- # Used by 'direct', 'resolve', and 'polymorphic' route helpers.
163
+ # Given a `name`, defines name_path and name_url helpers. Used by 'direct',
164
+ # 'resolve', and 'polymorphic' route helpers.
149
165
  def add_url_helper(name, defaults, &block)
150
166
  helper = CustomUrlHelper.new(name, defaults, &block)
151
167
  path_name = :"#{name}_path"
@@ -301,18 +317,18 @@ module ActionDispatch
301
317
  end
302
318
 
303
319
  private
304
- # Create a URL helper allowing ordered parameters to be associated
305
- # with corresponding dynamic segments, so you can do:
320
+ # Create a URL helper allowing ordered parameters to be associated with
321
+ # corresponding dynamic segments, so you can do:
306
322
  #
307
- # foo_url(bar, baz, bang)
323
+ # foo_url(bar, baz, bang)
308
324
  #
309
325
  # Instead of:
310
326
  #
311
- # foo_url(bar: bar, baz: baz, bang: bang)
327
+ # foo_url(bar: bar, baz: baz, bang: bang)
312
328
  #
313
329
  # Also allow options hash, so you can do:
314
330
  #
315
- # foo_url(bar, baz, bang, sort_by: 'baz')
331
+ # foo_url(bar, baz, bang, sort_by: 'baz')
316
332
  #
317
333
  def define_url_helper(mod, name, helper, url_strategy)
318
334
  mod.define_method(name) do |*args|
@@ -333,7 +349,7 @@ module ActionDispatch
333
349
  PATH = ->(options) { ActionDispatch::Http::URL.path_for(options) }
334
350
  UNKNOWN = ->(options) { ActionDispatch::Http::URL.url_for(options) }
335
351
 
336
- attr_accessor :formatter, :set, :named_routes, :default_scope, :router
352
+ attr_accessor :formatter, :set, :named_routes, :router
337
353
  attr_accessor :disable_clear_and_finalize, :resources_path_names
338
354
  attr_accessor :default_url_options, :draw_paths
339
355
  attr_reader :env_key, :polymorphic_mappings
@@ -345,7 +361,7 @@ module ActionDispatch
345
361
  end
346
362
 
347
363
  def self.new_with_config(config)
348
- route_set_config = DEFAULT_CONFIG
364
+ route_set_config = DEFAULT_CONFIG.dup
349
365
 
350
366
  # engines apparently don't have this set
351
367
  if config.respond_to? :relative_url_root
@@ -356,14 +372,18 @@ module ActionDispatch
356
372
  route_set_config.api_only = config.api_only
357
373
  end
358
374
 
375
+ if config.respond_to? :default_scope
376
+ route_set_config.default_scope = config.default_scope
377
+ end
378
+
359
379
  new route_set_config
360
380
  end
361
381
 
362
- Config = Struct.new :relative_url_root, :api_only
382
+ Config = Struct.new :relative_url_root, :api_only, :default_scope
363
383
 
364
- DEFAULT_CONFIG = Config.new(nil, false)
384
+ DEFAULT_CONFIG = Config.new(nil, false, nil)
365
385
 
366
- def initialize(config = DEFAULT_CONFIG)
386
+ def initialize(config = DEFAULT_CONFIG.dup)
367
387
  self.named_routes = NamedRouteCollection.new
368
388
  self.resources_path_names = self.class.default_resources_path_names
369
389
  self.default_url_options = {}
@@ -386,6 +406,7 @@ module ActionDispatch
386
406
  def eager_load!
387
407
  router.eager_load!
388
408
  routes.each(&:eager_load!)
409
+ formatter.eager_load!
389
410
  nil
390
411
  end
391
412
 
@@ -397,6 +418,14 @@ module ActionDispatch
397
418
  @config.api_only
398
419
  end
399
420
 
421
+ def default_scope
422
+ @config.default_scope
423
+ end
424
+
425
+ def default_scope=(new_default_scope)
426
+ @config.default_scope = new_default_scope
427
+ end
428
+
400
429
  def request_class
401
430
  ActionDispatch::Request
402
431
  end
@@ -470,10 +499,9 @@ module ActionDispatch
470
499
  include UrlFor
471
500
  end
472
501
 
473
- # Contains all the mounted helpers across different
474
- # engines and the `main_app` helper for the application.
475
- # You can include this in your classes if you want to
476
- # access routes for other engines.
502
+ # Contains all the mounted helpers across different engines and the `main_app`
503
+ # helper for the application. You can include this in your classes if you want
504
+ # to access routes for other engines.
477
505
  def mounted_helpers
478
506
  MountedHelpers
479
507
  end
@@ -563,13 +591,11 @@ module ActionDispatch
563
591
 
564
592
  url_helpers = routes.named_routes.url_helpers_module
565
593
 
566
- # Make named_routes available in the module singleton
567
- # as well, so one can do:
594
+ # Make named_routes available in the module singleton as well, so one can do:
568
595
  # Rails.application.routes.url_helpers.posts_path
569
596
  extend url_helpers
570
597
 
571
- # Any class that includes this module will get all
572
- # named routes...
598
+ # Any class that includes this module will get all named routes...
573
599
  include url_helpers
574
600
 
575
601
  if supports_path
@@ -584,9 +610,8 @@ module ActionDispatch
584
610
  redefine_singleton_method(:_routes) { routes }
585
611
  end
586
612
 
587
- # And an instance method _routes. Note that
588
- # UrlFor (included in this module) add extra
589
- # conveniences for working with @_routes.
613
+ # And an instance method _routes. Note that UrlFor (included in this module) add
614
+ # extra conveniences for working with @_routes.
590
615
  define_method(:_routes) { @_routes || routes }
591
616
 
592
617
  define_method(:_generate_paths_by_default) do
@@ -595,12 +620,12 @@ module ActionDispatch
595
620
 
596
621
  private :_generate_paths_by_default
597
622
 
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.
623
+ # If the module is included more than once (for example, in a subclass of an
624
+ # ancestor that includes the module), ensure that the `_routes` singleton and
625
+ # instance methods return the desired route set by including a new copy of the
626
+ # module (recursively if necessary). Note that this method is called for each
627
+ # inclusion, whereas the above `included` block is run only for the initial
628
+ # inclusion of each copy.
604
629
  def self.included(base)
605
630
  super
606
631
  if base.respond_to?(:_routes) && !base._routes.equal?(@_proxy._routes)
@@ -632,14 +657,14 @@ module ActionDispatch
632
657
  if route.segment_keys.include?(:controller)
633
658
  ActionDispatch.deprecator.warn(<<-MSG.squish)
634
659
  Using a dynamic :controller segment in a route is deprecated and
635
- will be removed in Rails 7.2.
660
+ will be removed in Rails 9.0.
636
661
  MSG
637
662
  end
638
663
 
639
664
  if route.segment_keys.include?(:action)
640
665
  ActionDispatch.deprecator.warn(<<-MSG.squish)
641
666
  Using a dynamic :action segment in a route is deprecated and
642
- will be removed in Rails 7.2.
667
+ will be removed in Rails 9.0.
643
668
  MSG
644
669
  end
645
670
 
@@ -716,14 +741,14 @@ module ActionDispatch
716
741
  end
717
742
 
718
743
  def normalize_options!
719
- # If an explicit :controller was given, always make :action explicit
720
- # too, so that action expiry works as expected for things like
744
+ # If an explicit :controller was given, always make :action explicit too, so
745
+ # that action expiry works as expected for things like
721
746
  #
722
- # generate({controller: 'content'}, {controller: 'content', action: 'show'})
747
+ # generate({controller: 'content'}, {controller: 'content', action: 'show'})
723
748
  #
724
- # (the above is from the unit tests). In the above case, because the
725
- # controller was explicitly given, but no action, the action is implied to
726
- # be "index", not the recalled action of "show".
749
+ # (the above is from the unit tests). In the above case, because the controller
750
+ # was explicitly given, but no action, the action is implied to be "index", not
751
+ # the recalled action of "show".
727
752
 
728
753
  if options[:controller]
729
754
  options[:action] ||= "index"
@@ -735,10 +760,9 @@ module ActionDispatch
735
760
  end
736
761
  end
737
762
 
738
- # This pulls :controller, :action, and :id out of the recall.
739
- # The recall key is only used if there is no key in the options
740
- # or if the key in the options is identical. If any of
741
- # :controller, :action or :id is not found, don't pull any
763
+ # This pulls :controller, :action, and :id out of the recall. The recall key is
764
+ # only used if there is no key in the options or if the key in the options is
765
+ # identical. If any of :controller, :action or :id is not found, don't pull any
742
766
  # more keys from the recall.
743
767
  def normalize_controller_action_id!
744
768
  use_recall_for(:controller) || return
@@ -746,8 +770,8 @@ module ActionDispatch
746
770
  use_recall_for(:id)
747
771
  end
748
772
 
749
- # if the current controller is "foo/bar/baz" and controller: "baz/bat"
750
- # is specified, the controller becomes "foo/baz/bat"
773
+ # if the current controller is "foo/bar/baz" and controller: "baz/bat" is
774
+ # specified, the controller becomes "foo/baz/bat"
751
775
  def use_relative_controller!
752
776
  if !named_route && different_controller? && !controller.start_with?("/")
753
777
  old_parts = current_controller.split("/")
@@ -789,8 +813,8 @@ module ActionDispatch
789
813
  end
790
814
  end
791
815
 
792
- # Generate the path indicated by the arguments, and return an array of
793
- # the keys that were not used to generate it.
816
+ # Generate the path indicated by the arguments, and return an array of the keys
817
+ # that were not used to generate it.
794
818
  def extra_keys(options, recall = {})
795
819
  generate_extras(options, recall).last
796
820
  end
@@ -827,7 +851,7 @@ module ActionDispatch
827
851
  url_for(options, route_name, PATH, nil, reserved)
828
852
  end
829
853
 
830
- # The +options+ argument must be a hash whose keys are *symbols*.
854
+ # The `options` argument must be a hash whose keys are **symbols**.
831
855
  def url_for(options, route_name = nil, url_strategy = UNKNOWN, method_name = nil, reserved = RESERVED_OPTIONS)
832
856
  options = default_url_options.merge options
833
857
 
@@ -860,7 +884,7 @@ module ActionDispatch
860
884
  params = route_with_params.params
861
885
 
862
886
  if options.key? :params
863
- if options[:params]&.respond_to?(:to_hash)
887
+ if options[:params].respond_to?(:to_hash)
864
888
  params.merge! options[:params]
865
889
  else
866
890
  params[:params] = options[:params]
@@ -903,7 +927,7 @@ module ActionDispatch
903
927
  params.each do |key, value|
904
928
  if value.is_a?(String)
905
929
  value = value.dup.force_encoding(Encoding::BINARY)
906
- params[key] = RFC2396_PARSER.unescape(value)
930
+ params[key] = URI::RFC2396_PARSER.unescape(value)
907
931
  end
908
932
  end
909
933
  req.path_parameters = params
@@ -927,6 +951,5 @@ module ActionDispatch
927
951
  end
928
952
  end
929
953
  end
930
- # :startdoc:
931
954
  end
932
955
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "active_support/core_ext/array/extract_options"
4
6
 
5
7
  module ActionDispatch
@@ -46,12 +48,13 @@ module ActionDispatch
46
48
  end
47
49
  end
48
50
 
49
- # Keeps the part of the script name provided by the global
50
- # context via ENV["SCRIPT_NAME"], which `mount` doesn't know
51
- # about since it depends on the specific request, but use our
52
- # script name resolver for the mount point dependent part.
51
+ # Keeps the part of the script name provided by the global context via
52
+ # [ENV]("SCRIPT_NAME"), which `mount` doesn't know about since it depends on the
53
+ # specific request, but use our script name resolver for the mount point
54
+ # dependent part.
53
55
  def merge_script_names(previous_script_name, new_script_name)
54
56
  return new_script_name unless previous_script_name
57
+ new_script_name = new_script_name.chomp("/")
55
58
 
56
59
  resolved_parts = new_script_name.count("/")
57
60
  previous_parts = previous_script_name.count("/")