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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +308 -523
- data/README.rdoc +1 -1
- data/lib/abstract_controller/asset_paths.rb +6 -2
- data/lib/abstract_controller/base.rb +104 -105
- data/lib/abstract_controller/caching/fragments.rb +50 -53
- data/lib/abstract_controller/caching.rb +8 -3
- data/lib/abstract_controller/callbacks.rb +70 -62
- data/lib/abstract_controller/collector.rb +7 -7
- data/lib/abstract_controller/deprecator.rb +2 -0
- data/lib/abstract_controller/error.rb +2 -0
- data/lib/abstract_controller/helpers.rb +71 -84
- data/lib/abstract_controller/logger.rb +4 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -0
- data/lib/abstract_controller/rendering.rb +13 -13
- data/lib/abstract_controller/translation.rb +12 -13
- data/lib/abstract_controller/url_for.rb +8 -6
- data/lib/abstract_controller.rb +2 -0
- data/lib/action_controller/api/api_rendering.rb +2 -0
- data/lib/action_controller/api.rb +76 -72
- data/lib/action_controller/base.rb +199 -126
- data/lib/action_controller/caching.rb +16 -14
- data/lib/action_controller/deprecator.rb +2 -0
- data/lib/action_controller/form_builder.rb +21 -18
- data/lib/action_controller/log_subscriber.rb +23 -2
- data/lib/action_controller/metal/allow_browser.rb +133 -0
- data/lib/action_controller/metal/basic_implicit_render.rb +2 -0
- data/lib/action_controller/metal/conditional_get.rb +217 -175
- data/lib/action_controller/metal/content_security_policy.rb +25 -24
- data/lib/action_controller/metal/cookies.rb +4 -2
- data/lib/action_controller/metal/data_streaming.rb +72 -63
- data/lib/action_controller/metal/default_headers.rb +5 -3
- data/lib/action_controller/metal/etag_with_flash.rb +3 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +17 -15
- data/lib/action_controller/metal/exceptions.rb +16 -9
- data/lib/action_controller/metal/flash.rb +13 -14
- data/lib/action_controller/metal/head.rb +15 -11
- data/lib/action_controller/metal/helpers.rb +63 -55
- data/lib/action_controller/metal/http_authentication.rb +209 -201
- data/lib/action_controller/metal/implicit_render.rb +17 -15
- data/lib/action_controller/metal/instrumentation.rb +16 -14
- data/lib/action_controller/metal/live.rb +177 -128
- data/lib/action_controller/metal/logging.rb +6 -4
- data/lib/action_controller/metal/mime_responds.rb +151 -142
- data/lib/action_controller/metal/parameter_encoding.rb +34 -32
- data/lib/action_controller/metal/params_wrapper.rb +57 -59
- data/lib/action_controller/metal/permissions_policy.rb +22 -12
- data/lib/action_controller/metal/rate_limiting.rb +92 -0
- data/lib/action_controller/metal/redirecting.rb +213 -94
- data/lib/action_controller/metal/renderers.rb +78 -57
- data/lib/action_controller/metal/rendering.rb +111 -77
- data/lib/action_controller/metal/request_forgery_protection.rb +182 -143
- data/lib/action_controller/metal/rescue.rb +20 -9
- data/lib/action_controller/metal/streaming.rb +118 -195
- data/lib/action_controller/metal/strong_parameters.rb +720 -530
- data/lib/action_controller/metal/testing.rb +2 -0
- data/lib/action_controller/metal/url_for.rb +17 -15
- data/lib/action_controller/metal.rb +86 -60
- data/lib/action_controller/railtie.rb +36 -15
- data/lib/action_controller/railties/helpers.rb +2 -0
- data/lib/action_controller/renderer.rb +41 -36
- data/lib/action_controller/structured_event_subscriber.rb +116 -0
- data/lib/action_controller/template_assertions.rb +4 -2
- data/lib/action_controller/test_case.rb +160 -131
- data/lib/action_controller.rb +5 -1
- data/lib/action_dispatch/constants.rb +8 -0
- data/lib/action_dispatch/deprecator.rb +2 -0
- data/lib/action_dispatch/http/cache.rb +163 -35
- data/lib/action_dispatch/http/content_disposition.rb +2 -0
- data/lib/action_dispatch/http/content_security_policy.rb +54 -39
- data/lib/action_dispatch/http/filter_parameters.rb +14 -8
- data/lib/action_dispatch/http/filter_redirect.rb +22 -1
- data/lib/action_dispatch/http/headers.rb +22 -22
- data/lib/action_dispatch/http/mime_negotiation.rb +89 -41
- data/lib/action_dispatch/http/mime_type.rb +25 -21
- data/lib/action_dispatch/http/mime_types.rb +3 -0
- data/lib/action_dispatch/http/param_builder.rb +187 -0
- data/lib/action_dispatch/http/param_error.rb +26 -0
- data/lib/action_dispatch/http/parameters.rb +14 -12
- data/lib/action_dispatch/http/permissions_policy.rb +25 -36
- data/lib/action_dispatch/http/query_parser.rb +55 -0
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +141 -92
- data/lib/action_dispatch/http/response.rb +137 -77
- data/lib/action_dispatch/http/upload.rb +18 -16
- data/lib/action_dispatch/http/url.rb +187 -89
- data/lib/action_dispatch/journey/formatter.rb +21 -9
- data/lib/action_dispatch/journey/gtg/builder.rb +4 -3
- data/lib/action_dispatch/journey/gtg/simulator.rb +34 -11
- data/lib/action_dispatch/journey/gtg/transition_table.rb +47 -53
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -0
- data/lib/action_dispatch/journey/nodes/node.rb +8 -6
- data/lib/action_dispatch/journey/parser.rb +99 -195
- data/lib/action_dispatch/journey/path/pattern.rb +4 -1
- data/lib/action_dispatch/journey/route.rb +54 -38
- data/lib/action_dispatch/journey/router/utils.rb +22 -27
- data/lib/action_dispatch/journey/router.rb +63 -83
- data/lib/action_dispatch/journey/routes.rb +11 -2
- data/lib/action_dispatch/journey/scanner.rb +46 -42
- data/lib/action_dispatch/journey/visitors.rb +57 -23
- data/lib/action_dispatch/journey/visualizer/fsm.js +4 -6
- data/lib/action_dispatch/journey.rb +2 -0
- data/lib/action_dispatch/log_subscriber.rb +7 -1
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +2 -0
- data/lib/action_dispatch/middleware/assume_ssl.rb +8 -5
- data/lib/action_dispatch/middleware/callbacks.rb +3 -1
- data/lib/action_dispatch/middleware/cookies.rb +125 -106
- data/lib/action_dispatch/middleware/debug_exceptions.rb +37 -8
- data/lib/action_dispatch/middleware/debug_locks.rb +15 -13
- data/lib/action_dispatch/middleware/debug_view.rb +13 -5
- data/lib/action_dispatch/middleware/exception_wrapper.rb +18 -23
- data/lib/action_dispatch/middleware/executor.rb +19 -4
- data/lib/action_dispatch/middleware/flash.rb +63 -51
- data/lib/action_dispatch/middleware/host_authorization.rb +17 -15
- data/lib/action_dispatch/middleware/public_exceptions.rb +14 -12
- data/lib/action_dispatch/middleware/reloader.rb +5 -3
- data/lib/action_dispatch/middleware/remote_ip.rb +87 -77
- data/lib/action_dispatch/middleware/request_id.rb +16 -10
- data/lib/action_dispatch/middleware/server_timing.rb +4 -2
- data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +30 -8
- data/lib/action_dispatch/middleware/session/cookie_store.rb +27 -26
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +7 -3
- data/lib/action_dispatch/middleware/show_exceptions.rb +16 -16
- data/lib/action_dispatch/middleware/ssl.rb +53 -40
- data/lib/action_dispatch/middleware/stack.rb +11 -10
- data/lib/action_dispatch/middleware/static.rb +33 -31
- data/lib/action_dispatch/middleware/templates/rescues/_copy_button.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +3 -5
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +9 -5
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -0
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +50 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +1 -1
- data/lib/action_dispatch/railtie.rb +23 -3
- data/lib/action_dispatch/request/session.rb +24 -21
- data/lib/action_dispatch/request/utils.rb +11 -3
- data/lib/action_dispatch/routing/endpoint.rb +2 -0
- data/lib/action_dispatch/routing/inspector.rb +85 -60
- data/lib/action_dispatch/routing/mapper.rb +1031 -851
- data/lib/action_dispatch/routing/polymorphic_routes.rb +69 -62
- data/lib/action_dispatch/routing/redirection.rb +47 -39
- data/lib/action_dispatch/routing/route_set.rb +79 -56
- data/lib/action_dispatch/routing/routes_proxy.rb +7 -4
- data/lib/action_dispatch/routing/url_for.rb +130 -125
- data/lib/action_dispatch/routing.rb +150 -148
- data/lib/action_dispatch/structured_event_subscriber.rb +20 -0
- data/lib/action_dispatch/system_test_case.rb +91 -81
- data/lib/action_dispatch/system_testing/browser.rb +16 -23
- data/lib/action_dispatch/system_testing/driver.rb +2 -0
- data/lib/action_dispatch/system_testing/server.rb +2 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +34 -23
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +2 -0
- data/lib/action_dispatch/testing/assertion_response.rb +9 -7
- data/lib/action_dispatch/testing/assertions/response.rb +52 -25
- data/lib/action_dispatch/testing/assertions/routing.rb +168 -87
- data/lib/action_dispatch/testing/assertions.rb +2 -0
- data/lib/action_dispatch/testing/integration.rb +233 -223
- data/lib/action_dispatch/testing/request_encoder.rb +11 -9
- data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
- data/lib/action_dispatch/testing/test_process.rb +11 -8
- data/lib/action_dispatch/testing/test_request.rb +3 -1
- data/lib/action_dispatch/testing/test_response.rb +27 -26
- data/lib/action_dispatch.rb +36 -32
- data/lib/action_pack/gem_version.rb +6 -4
- data/lib/action_pack/version.rb +3 -1
- data/lib/action_pack.rb +17 -16
- metadata +36 -32
- data/lib/action_dispatch/journey/parser.y +0 -50
- 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
|
-
#
|
|
7
|
+
# # Action Dispatch Routing PolymorphicRoutes
|
|
6
8
|
#
|
|
7
|
-
# Polymorphic URL helpers are methods for smart resolution to a named route call
|
|
8
|
-
# given an Active Record model instance. They are to be used in combination
|
|
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
|
|
12
|
-
# resource without having to know the exact type of the record in
|
|
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
|
|
17
|
+
# Nested resources and/or namespaces are also supported, as illustrated in the
|
|
18
|
+
# example:
|
|
15
19
|
#
|
|
16
|
-
#
|
|
20
|
+
# polymorphic_url([:admin, @article, @comment])
|
|
17
21
|
#
|
|
18
22
|
# results in:
|
|
19
23
|
#
|
|
20
|
-
#
|
|
24
|
+
# admin_article_comment_url(@article, @comment)
|
|
25
|
+
#
|
|
26
|
+
# ## Usage within the framework
|
|
21
27
|
#
|
|
22
|
-
#
|
|
28
|
+
# Polymorphic URL helpers are used in a number of places throughout the Rails
|
|
29
|
+
# framework:
|
|
23
30
|
#
|
|
24
|
-
#
|
|
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
|
-
#
|
|
42
|
+
# ## Prefixed polymorphic helpers
|
|
37
43
|
#
|
|
38
|
-
# In addition to
|
|
39
|
-
#
|
|
40
|
-
#
|
|
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
|
-
#
|
|
48
|
-
#
|
|
54
|
+
# edit_polymorphic_path(@post) # => "/posts/1/edit"
|
|
55
|
+
# polymorphic_path(@post, format: :pdf) # => "/posts/1.pdf"
|
|
49
56
|
#
|
|
50
|
-
#
|
|
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
|
-
#
|
|
57
|
-
#
|
|
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
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
|
78
|
-
#
|
|
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
|
-
#
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
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
|
|
92
|
+
# For all of these options, see the documentation for
|
|
93
|
+
# [url_for](rdoc-ref:ActionDispatch::Routing::UrlFor).
|
|
87
94
|
#
|
|
88
|
-
#
|
|
95
|
+
# #### Functionality
|
|
89
96
|
#
|
|
90
|
-
#
|
|
91
|
-
#
|
|
97
|
+
# # an Article record
|
|
98
|
+
# polymorphic_url(record) # same as article_url(record)
|
|
92
99
|
#
|
|
93
|
-
#
|
|
94
|
-
#
|
|
100
|
+
# # a Comment record
|
|
101
|
+
# polymorphic_url(record) # same as comment_url(record)
|
|
95
102
|
#
|
|
96
|
-
#
|
|
97
|
-
#
|
|
98
|
-
#
|
|
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
|
-
#
|
|
101
|
-
#
|
|
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
|
-
#
|
|
153
|
+
# get "/stories" => redirect("/posts")
|
|
150
154
|
#
|
|
151
|
-
# This will redirect the user, while ignoring certain parts of the request,
|
|
152
|
-
#
|
|
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
|
|
155
|
-
#
|
|
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
|
-
#
|
|
162
|
+
# get "/stories" => redirect("/posts", status: 307)
|
|
158
163
|
#
|
|
159
164
|
# You can also use interpolation in the supplied redirect argument:
|
|
160
165
|
#
|
|
161
|
-
#
|
|
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
|
|
164
|
-
# current SCRIPT_NAME environment variable. This is typically
|
|
165
|
-
# a mounted engine or where the application is
|
|
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
|
|
170
|
-
# the redirect in question. Either the params and request are
|
|
171
|
-
# params, depending of how many arguments your
|
|
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
|
-
#
|
|
175
|
-
#
|
|
176
|
-
#
|
|
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
|
|
180
|
-
# the block to
|
|
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
|
|
183
|
-
# to change, it also supports interpolation of the path similar to
|
|
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
|
-
#
|
|
186
|
-
#
|
|
187
|
-
#
|
|
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
|
|
190
|
-
# for example the
|
|
191
|
-
#
|
|
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,
|
|
194
|
-
# common redirect routes. The call method must accept two
|
|
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
|
-
#
|
|
204
|
+
# get 'accounts/:name' => redirect(SubdomainRedirector.new('api'))
|
|
198
205
|
#
|
|
199
206
|
def redirect(*args, &block)
|
|
200
|
-
options
|
|
201
|
-
status
|
|
202
|
-
path
|
|
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
|
-
#
|
|
15
|
+
# The RouteSet contains a collection of Route instances, representing the routes
|
|
16
|
+
# typically defined in `config/routes.rb`.
|
|
14
17
|
class RouteSet
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
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
|
|
148
|
-
#
|
|
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
|
-
#
|
|
320
|
+
# Create a URL helper allowing ordered parameters to be associated with
|
|
321
|
+
# corresponding dynamic segments, so you can do:
|
|
306
322
|
#
|
|
307
|
-
#
|
|
323
|
+
# foo_url(bar, baz, bang)
|
|
308
324
|
#
|
|
309
325
|
# Instead of:
|
|
310
326
|
#
|
|
311
|
-
#
|
|
327
|
+
# foo_url(bar: bar, baz: baz, bang: bang)
|
|
312
328
|
#
|
|
313
329
|
# Also allow options hash, so you can do:
|
|
314
330
|
#
|
|
315
|
-
#
|
|
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, :
|
|
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
|
-
#
|
|
475
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
600
|
-
#
|
|
601
|
-
#
|
|
602
|
-
#
|
|
603
|
-
#
|
|
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
|
|
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
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
726
|
-
#
|
|
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
|
-
#
|
|
740
|
-
#
|
|
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
|
-
#
|
|
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
|
-
#
|
|
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
|
|
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]
|
|
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
|
-
#
|
|
51
|
-
#
|
|
52
|
-
#
|
|
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("/")
|