actionpack 7.0.4 → 7.1.3.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +397 -269
- data/MIT-LICENSE +1 -1
- data/README.rdoc +4 -4
- data/lib/abstract_controller/base.rb +20 -11
- data/lib/abstract_controller/caching/fragments.rb +2 -0
- data/lib/abstract_controller/callbacks.rb +31 -6
- data/lib/abstract_controller/deprecator.rb +7 -0
- data/lib/abstract_controller/helpers.rb +75 -28
- data/lib/abstract_controller/railties/routes_helpers.rb +1 -16
- data/lib/abstract_controller/rendering.rb +12 -14
- data/lib/abstract_controller/translation.rb +9 -6
- data/lib/abstract_controller/url_for.rb +2 -0
- data/lib/abstract_controller.rb +6 -0
- data/lib/action_controller/api.rb +6 -4
- data/lib/action_controller/base.rb +3 -17
- data/lib/action_controller/caching.rb +2 -0
- data/lib/action_controller/deprecator.rb +7 -0
- data/lib/action_controller/form_builder.rb +2 -0
- data/lib/action_controller/log_subscriber.rb +16 -4
- data/lib/action_controller/metal/basic_implicit_render.rb +3 -1
- data/lib/action_controller/metal/conditional_get.rb +121 -123
- data/lib/action_controller/metal/content_security_policy.rb +5 -5
- data/lib/action_controller/metal/data_streaming.rb +20 -18
- data/lib/action_controller/metal/default_headers.rb +2 -0
- data/lib/action_controller/metal/etag_with_flash.rb +3 -1
- data/lib/action_controller/metal/etag_with_template_digest.rb +2 -0
- data/lib/action_controller/metal/exceptions.rb +8 -0
- data/lib/action_controller/metal/head.rb +9 -7
- data/lib/action_controller/metal/helpers.rb +3 -14
- data/lib/action_controller/metal/http_authentication.rb +17 -8
- data/lib/action_controller/metal/implicit_render.rb +5 -3
- data/lib/action_controller/metal/instrumentation.rb +8 -1
- data/lib/action_controller/metal/live.rb +25 -1
- data/lib/action_controller/metal/mime_responds.rb +2 -2
- data/lib/action_controller/metal/params_wrapper.rb +4 -2
- data/lib/action_controller/metal/permissions_policy.rb +2 -2
- data/lib/action_controller/metal/redirecting.rb +29 -8
- data/lib/action_controller/metal/renderers.rb +4 -4
- data/lib/action_controller/metal/rendering.rb +114 -9
- data/lib/action_controller/metal/request_forgery_protection.rb +144 -53
- data/lib/action_controller/metal/rescue.rb +6 -3
- data/lib/action_controller/metal/streaming.rb +71 -31
- data/lib/action_controller/metal/strong_parameters.rb +158 -101
- data/lib/action_controller/metal/url_for.rb +9 -4
- data/lib/action_controller/metal.rb +79 -21
- data/lib/action_controller/railtie.rb +24 -10
- data/lib/action_controller/renderer.rb +99 -85
- data/lib/action_controller/test_case.rb +15 -5
- data/lib/action_controller.rb +8 -1
- data/lib/action_dispatch/constants.rb +32 -0
- data/lib/action_dispatch/deprecator.rb +7 -0
- data/lib/action_dispatch/http/cache.rb +9 -11
- data/lib/action_dispatch/http/content_security_policy.rb +14 -9
- data/lib/action_dispatch/http/filter_parameters.rb +14 -28
- data/lib/action_dispatch/http/headers.rb +3 -1
- data/lib/action_dispatch/http/mime_negotiation.rb +22 -22
- data/lib/action_dispatch/http/mime_type.rb +35 -12
- data/lib/action_dispatch/http/mime_types.rb +3 -1
- data/lib/action_dispatch/http/parameters.rb +1 -1
- data/lib/action_dispatch/http/permissions_policy.rb +38 -23
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +63 -30
- data/lib/action_dispatch/http/response.rb +80 -63
- data/lib/action_dispatch/http/upload.rb +15 -2
- data/lib/action_dispatch/journey/formatter.rb +8 -2
- data/lib/action_dispatch/journey/path/pattern.rb +14 -14
- data/lib/action_dispatch/journey/route.rb +3 -2
- data/lib/action_dispatch/journey/router.rb +9 -8
- data/lib/action_dispatch/journey/routes.rb +2 -2
- data/lib/action_dispatch/log_subscriber.rb +23 -0
- data/lib/action_dispatch/middleware/actionable_exceptions.rb +5 -6
- data/lib/action_dispatch/middleware/assume_ssl.rb +24 -0
- data/lib/action_dispatch/middleware/callbacks.rb +2 -0
- data/lib/action_dispatch/middleware/cookies.rb +108 -117
- data/lib/action_dispatch/middleware/debug_exceptions.rb +26 -25
- data/lib/action_dispatch/middleware/debug_locks.rb +4 -1
- data/lib/action_dispatch/middleware/debug_view.rb +7 -2
- data/lib/action_dispatch/middleware/exception_wrapper.rb +186 -27
- data/lib/action_dispatch/middleware/executor.rb +1 -1
- data/lib/action_dispatch/middleware/flash.rb +7 -0
- data/lib/action_dispatch/middleware/host_authorization.rb +18 -8
- data/lib/action_dispatch/middleware/public_exceptions.rb +5 -3
- data/lib/action_dispatch/middleware/reloader.rb +7 -5
- data/lib/action_dispatch/middleware/remote_ip.rb +21 -20
- data/lib/action_dispatch/middleware/request_id.rb +4 -2
- data/lib/action_dispatch/middleware/server_timing.rb +4 -4
- data/lib/action_dispatch/middleware/session/abstract_store.rb +5 -0
- data/lib/action_dispatch/middleware/session/cache_store.rb +2 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +11 -5
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +3 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +25 -18
- data/lib/action_dispatch/middleware/ssl.rb +18 -6
- data/lib/action_dispatch/middleware/stack.rb +7 -2
- data/lib/action_dispatch/middleware/static.rb +14 -10
- data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -3
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -3
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +7 -7
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +17 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +16 -12
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +3 -3
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
- data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +3 -0
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +59 -41
- data/lib/action_dispatch/railtie.rb +14 -4
- data/lib/action_dispatch/request/session.rb +16 -6
- data/lib/action_dispatch/request/utils.rb +8 -3
- data/lib/action_dispatch/routing/inspector.rb +54 -6
- data/lib/action_dispatch/routing/mapper.rb +58 -24
- data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -0
- data/lib/action_dispatch/routing/redirection.rb +15 -6
- data/lib/action_dispatch/routing/route_set.rb +52 -22
- data/lib/action_dispatch/routing/routes_proxy.rb +10 -15
- data/lib/action_dispatch/routing/url_for.rb +26 -22
- data/lib/action_dispatch/routing.rb +7 -7
- data/lib/action_dispatch/system_test_case.rb +3 -3
- data/lib/action_dispatch/system_testing/browser.rb +20 -19
- data/lib/action_dispatch/system_testing/driver.rb +14 -22
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +27 -16
- data/lib/action_dispatch/testing/assertion_response.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +14 -7
- data/lib/action_dispatch/testing/assertions/routing.rb +67 -28
- data/lib/action_dispatch/testing/assertions.rb +3 -1
- data/lib/action_dispatch/testing/integration.rb +27 -17
- data/lib/action_dispatch/testing/request_encoder.rb +4 -1
- data/lib/action_dispatch/testing/test_process.rb +4 -3
- data/lib/action_dispatch/testing/test_request.rb +1 -1
- data/lib/action_dispatch/testing/test_response.rb +23 -9
- data/lib/action_dispatch.rb +37 -4
- data/lib/action_pack/gem_version.rb +4 -4
- data/lib/action_pack/version.rb +1 -1
- data/lib/action_pack.rb +1 -1
- metadata +65 -29
@@ -1,24 +1,45 @@
|
|
1
1
|
<% content_for :style do %>
|
2
|
+
h2, p {
|
3
|
+
padding-left: 30px;
|
4
|
+
}
|
5
|
+
|
2
6
|
#route_table {
|
3
7
|
margin: 0;
|
4
8
|
border-collapse: collapse;
|
9
|
+
word-wrap:break-word;
|
10
|
+
table-layout: fixed;
|
11
|
+
width:100%;
|
5
12
|
}
|
6
13
|
|
7
14
|
#route_table thead tr {
|
8
15
|
border-bottom: 2px solid #ddd;
|
9
16
|
}
|
10
17
|
|
18
|
+
#route_table th {
|
19
|
+
padding-left: 30px;
|
20
|
+
text-align: left;
|
21
|
+
}
|
22
|
+
|
11
23
|
#route_table thead tr.bottom {
|
12
24
|
border-bottom: none;
|
13
25
|
}
|
14
26
|
|
15
27
|
#route_table thead tr.bottom th {
|
16
|
-
padding: 10px
|
28
|
+
padding: 10px 30px;
|
17
29
|
line-height: 15px;
|
18
30
|
}
|
19
31
|
|
20
|
-
#route_table
|
32
|
+
#route_table #search_container {
|
33
|
+
padding: 7px 30px;
|
34
|
+
}
|
35
|
+
|
36
|
+
#route_table thead tr th input#search {
|
21
37
|
-webkit-appearance: textfield;
|
38
|
+
width:100%;
|
39
|
+
}
|
40
|
+
|
41
|
+
#route_table thead th.http-verb {
|
42
|
+
width: 10%;
|
22
43
|
}
|
23
44
|
|
24
45
|
#route_table tbody tr {
|
@@ -45,11 +66,6 @@
|
|
45
66
|
padding: 4px 30px;
|
46
67
|
}
|
47
68
|
|
48
|
-
#path_search {
|
49
|
-
width: 80%;
|
50
|
-
font-size: inherit;
|
51
|
-
}
|
52
|
-
|
53
69
|
@media (prefers-color-scheme: dark) {
|
54
70
|
#route_table tbody tr:nth-child(odd) {
|
55
71
|
background: #282828;
|
@@ -62,28 +78,22 @@
|
|
62
78
|
}
|
63
79
|
<% end %>
|
64
80
|
|
65
|
-
<table id='route_table'
|
81
|
+
<table id='route_table'>
|
66
82
|
<thead>
|
67
83
|
<tr>
|
68
|
-
<th>Helper
|
69
|
-
|
70
|
-
<th>Path</th>
|
71
|
-
<th>Controller#Action</th>
|
72
|
-
</tr>
|
73
|
-
<tr class='bottom'>
|
74
|
-
<th><%# Helper %>
|
75
|
-
<%= link_to "Path", "#", 'data-route-helper' => '_path',
|
84
|
+
<th>Helper
|
85
|
+
(<%= link_to "Path", "#", 'data-route-helper' => '_path',
|
76
86
|
title: "Returns a relative path (without the http or domain)" %> /
|
77
87
|
<%= link_to "Url", "#", 'data-route-helper' => '_url',
|
78
|
-
title: "Returns an absolute URL (with the http and domain)" %>
|
79
|
-
</th>
|
80
|
-
<th><%# HTTP Verb %>
|
81
|
-
</th>
|
82
|
-
<th><%# Path %>
|
83
|
-
<%= search_field(:path, nil, id: 'search', placeholder: "Path Match") %>
|
84
|
-
</th>
|
85
|
-
<th><%# Controller#action %>
|
88
|
+
title: "Returns an absolute URL (with the http and domain)" %>)
|
86
89
|
</th>
|
90
|
+
<th class="http-verb">HTTP Verb</th>
|
91
|
+
<th>Path</th>
|
92
|
+
<th>Controller#Action</th>
|
93
|
+
<th>Source Location</th>
|
94
|
+
</tr>
|
95
|
+
<tr>
|
96
|
+
<th colspan="5" id="search_container"><%= search_field(:query, nil, id: 'search', placeholder: "Search") %></th>
|
87
97
|
</tr>
|
88
98
|
</thead>
|
89
99
|
<tbody class='exact_matches' id='exact_matches'>
|
@@ -99,12 +109,12 @@
|
|
99
109
|
// support forEach iterator on NodeList
|
100
110
|
NodeList.prototype.forEach = Array.prototype.forEach;
|
101
111
|
|
102
|
-
// Enables
|
103
|
-
function
|
112
|
+
// Enables query search functionality
|
113
|
+
function setupMatchingRoutes() {
|
104
114
|
// Check if there are any matched results in a section
|
105
|
-
function checkNoMatch(section,
|
115
|
+
function checkNoMatch(section, trElement) {
|
106
116
|
if (section.children.length <= 1) {
|
107
|
-
section.
|
117
|
+
section.appendChild(trElement);
|
108
118
|
}
|
109
119
|
}
|
110
120
|
|
@@ -128,8 +138,8 @@
|
|
128
138
|
}
|
129
139
|
|
130
140
|
// remove params or fragments
|
131
|
-
function
|
132
|
-
return
|
141
|
+
function sanitizeQuery(query) {
|
142
|
+
return query.replace(/[#?].*/, '');
|
133
143
|
}
|
134
144
|
|
135
145
|
var pathElements = document.querySelectorAll('#route_table [data-route-path]'),
|
@@ -145,26 +155,34 @@
|
|
145
155
|
}
|
146
156
|
}
|
147
157
|
|
158
|
+
function buildTr(string) {
|
159
|
+
var tr = document.createElement('tr');
|
160
|
+
var th = document.createElement('th');
|
161
|
+
th.setAttribute('colspan', 4);
|
162
|
+
tr.appendChild(th);
|
163
|
+
th.innerText = string;
|
164
|
+
return tr;
|
165
|
+
}
|
166
|
+
|
148
167
|
// On key press perform a search for matching paths
|
149
168
|
delayedKeyup(searchElem, function() {
|
150
|
-
var
|
151
|
-
defaultExactMatch =
|
152
|
-
defaultFuzzyMatch =
|
153
|
-
noExactMatch = '
|
154
|
-
noFuzzyMatch = '
|
169
|
+
var query = sanitizeQuery(searchElem.value),
|
170
|
+
defaultExactMatch = buildTr("Routes matching '" + query + "':"),
|
171
|
+
defaultFuzzyMatch = buildTr("Routes containing '" + query + "':"),
|
172
|
+
noExactMatch = buildTr('No exact matches found'),
|
173
|
+
noFuzzyMatch = buildTr('No fuzzy matches found');
|
155
174
|
|
156
|
-
if (!
|
175
|
+
if (!query)
|
157
176
|
return searchElem.onblur();
|
158
177
|
|
159
|
-
getJSON('/rails/info/routes?
|
178
|
+
getJSON('/rails/info/routes?query=' + query, function(matches){
|
160
179
|
// Clear out results section
|
161
|
-
exactSection.
|
162
|
-
fuzzySection.
|
180
|
+
exactSection.replaceChildren(defaultExactMatch);
|
181
|
+
fuzzySection.replaceChildren(defaultFuzzyMatch);
|
163
182
|
|
164
183
|
// Display exact matches and fuzzy matches
|
165
184
|
pathElements.forEach(function(elem) {
|
166
185
|
var elemPath = elem.getAttribute('data-route-path');
|
167
|
-
|
168
186
|
if (matches['exact'].indexOf(elemPath) != -1)
|
169
187
|
exactSection.appendChild(elem.parentNode.cloneNode(true));
|
170
188
|
|
@@ -206,7 +224,7 @@
|
|
206
224
|
});
|
207
225
|
}
|
208
226
|
|
209
|
-
|
227
|
+
setupMatchingRoutes();
|
210
228
|
setupRouteToggleHelperLinks();
|
211
229
|
|
212
230
|
// Focus the search input after page has loaded
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "action_dispatch"
|
4
|
+
require "action_dispatch/log_subscriber"
|
4
5
|
require "active_support/messages/rotation_configuration"
|
5
6
|
|
6
7
|
module ActionDispatch
|
@@ -8,7 +9,7 @@ module ActionDispatch
|
|
8
9
|
config.action_dispatch = ActiveSupport::OrderedOptions.new
|
9
10
|
config.action_dispatch.x_sendfile_header = nil
|
10
11
|
config.action_dispatch.ip_spoofing_check = true
|
11
|
-
config.action_dispatch.show_exceptions =
|
12
|
+
config.action_dispatch.show_exceptions = :all
|
12
13
|
config.action_dispatch.tld_length = 1
|
13
14
|
config.action_dispatch.ignore_accept_header = false
|
14
15
|
config.action_dispatch.rescue_templates = {}
|
@@ -23,9 +24,9 @@ module ActionDispatch
|
|
23
24
|
config.action_dispatch.use_authenticated_cookie_encryption = false
|
24
25
|
config.action_dispatch.use_cookies_with_metadata = false
|
25
26
|
config.action_dispatch.perform_deep_munge = true
|
26
|
-
config.action_dispatch.request_id_header =
|
27
|
-
config.action_dispatch.return_only_request_media_type_on_content_type = true
|
27
|
+
config.action_dispatch.request_id_header = ActionDispatch::Constants::X_REQUEST_ID
|
28
28
|
config.action_dispatch.log_rescued_responses = true
|
29
|
+
config.action_dispatch.debug_exception_log_level = :fatal
|
29
30
|
|
30
31
|
config.action_dispatch.default_headers = {
|
31
32
|
"X-Frame-Options" => "SAMEORIGIN",
|
@@ -40,13 +41,19 @@ module ActionDispatch
|
|
40
41
|
|
41
42
|
config.eager_load_namespaces << ActionDispatch
|
42
43
|
|
44
|
+
initializer "action_dispatch.deprecator", before: :load_environment_config do |app|
|
45
|
+
app.deprecators[:action_dispatch] = ActionDispatch.deprecator
|
46
|
+
end
|
47
|
+
|
43
48
|
initializer "action_dispatch.configure" do |app|
|
44
49
|
ActionDispatch::Http::URL.secure_protocol = app.config.force_ssl
|
45
50
|
ActionDispatch::Http::URL.tld_length = app.config.action_dispatch.tld_length
|
46
51
|
|
47
52
|
ActiveSupport.on_load(:action_dispatch_request) do
|
48
53
|
self.ignore_accept_header = app.config.action_dispatch.ignore_accept_header
|
49
|
-
|
54
|
+
unless app.config.action_dispatch.respond_to?(:return_only_request_media_type_on_content_type)
|
55
|
+
self.return_only_media_type_on_content_type = app.config.action_dispatch.return_only_request_media_type_on_content_type
|
56
|
+
end
|
50
57
|
ActionDispatch::Request::Utils.perform_deep_munge = app.config.action_dispatch.perform_deep_munge
|
51
58
|
end
|
52
59
|
|
@@ -61,6 +68,9 @@ module ActionDispatch
|
|
61
68
|
config.action_dispatch.always_write_cookie = Rails.env.development? if config.action_dispatch.always_write_cookie.nil?
|
62
69
|
ActionDispatch::Cookies::CookieJar.always_write_cookie = config.action_dispatch.always_write_cookie
|
63
70
|
|
71
|
+
ActionDispatch::Routing::Mapper.route_source_locations = Rails.env.development?
|
72
|
+
ActionDispatch::Routing::Mapper.backtrace_cleaner = Rails.backtrace_cleaner
|
73
|
+
|
64
74
|
ActionDispatch.test_app = app
|
65
75
|
end
|
66
76
|
end
|
@@ -78,6 +78,8 @@ module ActionDispatch
|
|
78
78
|
@loaded = false
|
79
79
|
@exists = nil # We haven't checked yet.
|
80
80
|
@enabled = enabled
|
81
|
+
@id_was = nil
|
82
|
+
@id_was_initialized = false
|
81
83
|
end
|
82
84
|
|
83
85
|
def id
|
@@ -176,9 +178,14 @@ module ActionDispatch
|
|
176
178
|
# session.to_hash
|
177
179
|
# # => {"session_id"=>"e29b9ea315edf98aad94cc78c34cc9b2", "foo" => "bar"}
|
178
180
|
def update(hash)
|
181
|
+
unless hash.respond_to?(:to_hash)
|
182
|
+
raise TypeError, "no implicit conversion of #{hash.class.name} into Hash"
|
183
|
+
end
|
184
|
+
|
179
185
|
load_for_write!
|
180
|
-
@delegate.update hash.stringify_keys
|
186
|
+
@delegate.update hash.to_hash.stringify_keys
|
181
187
|
end
|
188
|
+
alias :merge! :update
|
182
189
|
|
183
190
|
# Deletes given key from the session.
|
184
191
|
def delete(key)
|
@@ -232,15 +239,15 @@ module ActionDispatch
|
|
232
239
|
@delegate.empty?
|
233
240
|
end
|
234
241
|
|
235
|
-
def merge!(other)
|
236
|
-
load_for_write!
|
237
|
-
@delegate.merge!(other)
|
238
|
-
end
|
239
|
-
|
240
242
|
def each(&block)
|
241
243
|
to_hash.each(&block)
|
242
244
|
end
|
243
245
|
|
246
|
+
def id_was
|
247
|
+
load_for_read!
|
248
|
+
@id_was
|
249
|
+
end
|
250
|
+
|
244
251
|
private
|
245
252
|
def load_for_read!
|
246
253
|
load! if !loaded? && exists?
|
@@ -260,10 +267,13 @@ module ActionDispatch
|
|
260
267
|
|
261
268
|
def load!
|
262
269
|
if enabled?
|
270
|
+
@id_was_initialized = true unless exists?
|
263
271
|
id, session = @by.load_session @req
|
264
272
|
options[:id] = id
|
265
273
|
@delegate.replace(session.stringify_keys)
|
274
|
+
@id_was = id unless @id_was_initialized
|
266
275
|
end
|
276
|
+
@id_was_initialized = true
|
267
277
|
@loaded = true
|
268
278
|
end
|
269
279
|
end
|
@@ -55,9 +55,11 @@ module ActionDispatch
|
|
55
55
|
if params.has_key?(:tempfile)
|
56
56
|
ActionDispatch::Http::UploadedFile.new(params)
|
57
57
|
else
|
58
|
-
|
59
|
-
|
60
|
-
|
58
|
+
hwia = ActiveSupport::HashWithIndifferentAccess.new
|
59
|
+
params.each_pair do |key, val|
|
60
|
+
hwia[key] = normalize_encode_params(val)
|
61
|
+
end
|
62
|
+
hwia
|
61
63
|
end
|
62
64
|
else
|
63
65
|
params
|
@@ -83,6 +85,9 @@ module ActionDispatch
|
|
83
85
|
return params unless controller && controller.valid_encoding? && encoding_template = action_encoding_template(request, controller, action)
|
84
86
|
params.except(:controller, :action).each do |key, value|
|
85
87
|
ActionDispatch::Request::Utils.each_param_value(value) do |param|
|
88
|
+
# If `param` is frozen, it comes from the router defaults
|
89
|
+
next if param.frozen?
|
90
|
+
|
86
91
|
if encoding_template[key.to_s]
|
87
92
|
param.force_encoding(encoding_template[key.to_s])
|
88
93
|
end
|
@@ -6,8 +6,21 @@ require "io/console/size"
|
|
6
6
|
module ActionDispatch
|
7
7
|
module Routing
|
8
8
|
class RouteWrapper < SimpleDelegator # :nodoc:
|
9
|
+
def matches_filter?(filter, value)
|
10
|
+
return __getobj__.path.match(value) if filter == :exact_path_match
|
11
|
+
|
12
|
+
value.match?(public_send(filter))
|
13
|
+
end
|
14
|
+
|
9
15
|
def endpoint
|
10
|
-
|
16
|
+
case
|
17
|
+
when app.dispatcher?
|
18
|
+
"#{controller}##{action}"
|
19
|
+
when rack_app.is_a?(Proc)
|
20
|
+
"Inline handler (Proc/Lambda)"
|
21
|
+
else
|
22
|
+
rack_app.inspect
|
23
|
+
end
|
11
24
|
end
|
12
25
|
|
13
26
|
def constraints
|
@@ -85,8 +98,18 @@ module ActionDispatch
|
|
85
98
|
if filter[:controller]
|
86
99
|
{ controller: /#{filter[:controller].underscore.sub(/_?controller\z/, "")}/ }
|
87
100
|
elsif filter[:grep]
|
88
|
-
|
89
|
-
|
101
|
+
grep_pattern = Regexp.new(filter[:grep])
|
102
|
+
path = URI::DEFAULT_PARSER.escape(filter[:grep])
|
103
|
+
normalized_path = ("/" + path).squeeze("/")
|
104
|
+
|
105
|
+
{
|
106
|
+
controller: grep_pattern,
|
107
|
+
action: grep_pattern,
|
108
|
+
verb: grep_pattern,
|
109
|
+
name: grep_pattern,
|
110
|
+
path: grep_pattern,
|
111
|
+
exact_path_match: normalized_path,
|
112
|
+
}
|
90
113
|
end
|
91
114
|
end
|
92
115
|
|
@@ -94,7 +117,7 @@ module ActionDispatch
|
|
94
117
|
if filter
|
95
118
|
@routes.select do |route|
|
96
119
|
route_wrapper = RouteWrapper.new(route)
|
97
|
-
filter.any? { |
|
120
|
+
filter.any? { |filter_type, value| route_wrapper.matches_filter?(filter_type, value) }
|
98
121
|
end
|
99
122
|
else
|
100
123
|
@routes
|
@@ -110,7 +133,8 @@ module ActionDispatch
|
|
110
133
|
{ name: route.name,
|
111
134
|
verb: route.verb,
|
112
135
|
path: route.path,
|
113
|
-
reqs: route.reqs
|
136
|
+
reqs: route.reqs,
|
137
|
+
source_location: route.source_location }
|
114
138
|
end
|
115
139
|
end
|
116
140
|
|
@@ -216,13 +240,16 @@ module ActionDispatch
|
|
216
240
|
private
|
217
241
|
def draw_expanded_section(routes)
|
218
242
|
routes.map.each_with_index do |r, i|
|
219
|
-
<<~MESSAGE.chomp
|
243
|
+
route_rows = <<~MESSAGE.chomp
|
220
244
|
#{route_header(index: i + 1)}
|
221
245
|
Prefix | #{r[:name]}
|
222
246
|
Verb | #{r[:verb]}
|
223
247
|
URI | #{r[:path]}
|
224
248
|
Controller#Action | #{r[:reqs]}
|
225
249
|
MESSAGE
|
250
|
+
source_location = "\nSource Location | #{r[:source_location]}"
|
251
|
+
route_rows += source_location if r[:source_location].present?
|
252
|
+
route_rows
|
226
253
|
end
|
227
254
|
end
|
228
255
|
|
@@ -230,6 +257,27 @@ module ActionDispatch
|
|
230
257
|
"--[ Route #{index} ]".ljust(@width, "-")
|
231
258
|
end
|
232
259
|
end
|
260
|
+
|
261
|
+
class Unused < Sheet
|
262
|
+
def header(routes)
|
263
|
+
@buffer << <<~MSG
|
264
|
+
Found #{routes.count} unused #{"route".pluralize(routes.count)}:
|
265
|
+
MSG
|
266
|
+
|
267
|
+
super
|
268
|
+
end
|
269
|
+
|
270
|
+
def no_routes(routes, filter)
|
271
|
+
@buffer <<
|
272
|
+
if filter.none?
|
273
|
+
"No unused routes found."
|
274
|
+
elsif filter.key?(:controller)
|
275
|
+
"No unused routes found for this controller."
|
276
|
+
elsif filter.key?(:grep)
|
277
|
+
"No unused routes found for this grep pattern."
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
233
281
|
end
|
234
282
|
|
235
283
|
class HtmlTableFormatter
|
@@ -12,6 +12,9 @@ module ActionDispatch
|
|
12
12
|
class Mapper
|
13
13
|
URL_OPTIONS = [:protocol, :subdomain, :domain, :host, :port]
|
14
14
|
|
15
|
+
cattr_accessor :route_source_locations, instance_accessor: false, default: false
|
16
|
+
cattr_accessor :backtrace_cleaner, instance_accessor: false, default: ActiveSupport::BacktraceCleaner.new
|
17
|
+
|
15
18
|
class Constraints < Routing::Endpoint # :nodoc:
|
16
19
|
attr_reader :app, :constraints
|
17
20
|
|
@@ -43,7 +46,7 @@ module ActionDispatch
|
|
43
46
|
end
|
44
47
|
|
45
48
|
def serve(req)
|
46
|
-
return [ 404, {
|
49
|
+
return [ 404, { Constants::X_CASCADE => "pass" }, [] ] unless matches?(req)
|
47
50
|
|
48
51
|
@strategy.call @app, req
|
49
52
|
end
|
@@ -170,7 +173,7 @@ module ActionDispatch
|
|
170
173
|
Journey::Route.new(name: name, app: application, path: path, constraints: conditions,
|
171
174
|
required_defaults: required_defaults, defaults: defaults,
|
172
175
|
request_method_match: request_method, precedence: precedence,
|
173
|
-
scope_options: scope_options, internal: @internal)
|
176
|
+
scope_options: scope_options, internal: @internal, source_location: route_source_location)
|
174
177
|
end
|
175
178
|
|
176
179
|
def application
|
@@ -214,9 +217,16 @@ module ActionDispatch
|
|
214
217
|
if to.respond_to?(:action) || to.respond_to?(:call)
|
215
218
|
options
|
216
219
|
else
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
+
if to.nil?
|
221
|
+
controller = default_controller
|
222
|
+
action = default_action
|
223
|
+
elsif to.is_a?(String) && to.include?("#")
|
224
|
+
to_endpoint = to.split("#").map!(&:-@)
|
225
|
+
controller = to_endpoint[0]
|
226
|
+
action = to_endpoint[1]
|
227
|
+
else
|
228
|
+
raise ArgumentError, ":to must respond to `action` or `call`, or it must be a String that includes '#'"
|
229
|
+
end
|
220
230
|
|
221
231
|
controller = add_controller_module(controller, modyoule)
|
222
232
|
|
@@ -305,14 +315,6 @@ module ActionDispatch
|
|
305
315
|
hash
|
306
316
|
end
|
307
317
|
|
308
|
-
def split_to(to)
|
309
|
-
if /#/.match?(to)
|
310
|
-
to.split("#").map!(&:-@)
|
311
|
-
else
|
312
|
-
[]
|
313
|
-
end
|
314
|
-
end
|
315
|
-
|
316
318
|
def add_controller_module(controller, modyoule)
|
317
319
|
if modyoule && !controller.is_a?(Regexp)
|
318
320
|
if controller&.start_with?("/")
|
@@ -356,6 +358,15 @@ module ActionDispatch
|
|
356
358
|
def dispatcher(raise_on_name_error)
|
357
359
|
Routing::RouteSet::Dispatcher.new raise_on_name_error
|
358
360
|
end
|
361
|
+
|
362
|
+
def route_source_location
|
363
|
+
if Mapper.route_source_locations
|
364
|
+
action_dispatch_dir = File.expand_path("..", __dir__)
|
365
|
+
caller_location = caller_locations.find { |location| !location.path.include?(action_dispatch_dir) }
|
366
|
+
cleaned_path = Mapper.backtrace_cleaner.clean([caller_location.path]).first
|
367
|
+
"#{cleaned_path}:#{caller_location.lineno}" if cleaned_path
|
368
|
+
end
|
369
|
+
end
|
359
370
|
end
|
360
371
|
|
361
372
|
# Invokes Journey::Router::Utils.normalize_path, then ensures that
|
@@ -652,7 +663,7 @@ module ActionDispatch
|
|
652
663
|
|
653
664
|
script_namer = ->(options) do
|
654
665
|
prefix_options = options.slice(*_route.segment_keys)
|
655
|
-
prefix_options[:
|
666
|
+
prefix_options[:script_name] = "" if options[:original_script_name]
|
656
667
|
|
657
668
|
if options[:_recall]
|
658
669
|
prefix_options.reverse_merge!(options[:_recall].slice(*_route.segment_keys))
|
@@ -748,7 +759,7 @@ module ActionDispatch
|
|
748
759
|
# end
|
749
760
|
#
|
750
761
|
# This will create a number of routes for each of the posts and comments
|
751
|
-
# controller. For
|
762
|
+
# controller. For +Admin::PostsController+, \Rails will create:
|
752
763
|
#
|
753
764
|
# GET /admin/posts
|
754
765
|
# GET /admin/posts/new
|
@@ -759,7 +770,7 @@ module ActionDispatch
|
|
759
770
|
# DELETE /admin/posts/1
|
760
771
|
#
|
761
772
|
# If you want to route /posts (without the prefix /admin) to
|
762
|
-
#
|
773
|
+
# +Admin::PostsController+, you could use
|
763
774
|
#
|
764
775
|
# scope module: "admin" do
|
765
776
|
# resources :posts
|
@@ -808,7 +819,7 @@ module ActionDispatch
|
|
808
819
|
#
|
809
820
|
# Takes same options as <tt>Base#match</tt> and <tt>Resources#resources</tt>.
|
810
821
|
#
|
811
|
-
# # route /posts (without the prefix /admin) to
|
822
|
+
# # route /posts (without the prefix /admin) to +Admin::PostsController+
|
812
823
|
# scope module: "admin" do
|
813
824
|
# resources :posts
|
814
825
|
# end
|
@@ -917,7 +928,7 @@ module ActionDispatch
|
|
917
928
|
# resources :posts
|
918
929
|
# end
|
919
930
|
#
|
920
|
-
# # maps to
|
931
|
+
# # maps to +Sekret::PostsController+ rather than +Admin::PostsController+
|
921
932
|
# namespace :admin, module: "sekret" do
|
922
933
|
# resources :posts
|
923
934
|
# end
|
@@ -1318,7 +1329,7 @@ module ActionDispatch
|
|
1318
1329
|
self
|
1319
1330
|
end
|
1320
1331
|
|
1321
|
-
# In Rails, a resourceful route provides a mapping between HTTP verbs
|
1332
|
+
# In \Rails, a resourceful route provides a mapping between HTTP verbs
|
1322
1333
|
# and URLs and controller actions. By convention, each action also maps
|
1323
1334
|
# to particular CRUD operations in a database. A single entry in the
|
1324
1335
|
# routing file, such as
|
@@ -1450,7 +1461,7 @@ module ActionDispatch
|
|
1450
1461
|
#
|
1451
1462
|
# === Examples
|
1452
1463
|
#
|
1453
|
-
# # routes call
|
1464
|
+
# # routes call +Admin::PostsController+
|
1454
1465
|
# resources :posts, module: "admin"
|
1455
1466
|
#
|
1456
1467
|
# # resource actions are at /admin/posts.
|
@@ -1493,7 +1504,7 @@ module ActionDispatch
|
|
1493
1504
|
# end
|
1494
1505
|
# end
|
1495
1506
|
#
|
1496
|
-
# This will enable Rails to recognize paths such as <tt>/photos/search</tt>
|
1507
|
+
# This will enable \Rails to recognize paths such as <tt>/photos/search</tt>
|
1497
1508
|
# with GET, and route to the search action of +PhotosController+. It will also
|
1498
1509
|
# create the <tt>search_photos_url</tt> and <tt>search_photos_path</tt>
|
1499
1510
|
# route helpers.
|
@@ -1584,6 +1595,29 @@ module ActionDispatch
|
|
1584
1595
|
!parent_resource.singleton? && @scope[:shallow]
|
1585
1596
|
end
|
1586
1597
|
|
1598
|
+
# Loads another routes file with the given +name+ located inside the
|
1599
|
+
# +config/routes+ directory. In that file, you can use the normal
|
1600
|
+
# routing DSL, but <i>do not</i> surround it with a
|
1601
|
+
# +Rails.application.routes.draw+ block.
|
1602
|
+
#
|
1603
|
+
# # config/routes.rb
|
1604
|
+
# Rails.application.routes.draw do
|
1605
|
+
# draw :admin # Loads `config/routes/admin.rb`
|
1606
|
+
# draw "third_party/some_gem" # Loads `config/routes/third_party/some_gem.rb`
|
1607
|
+
# end
|
1608
|
+
#
|
1609
|
+
# # config/routes/admin.rb
|
1610
|
+
# namespace :admin do
|
1611
|
+
# resources :accounts
|
1612
|
+
# end
|
1613
|
+
#
|
1614
|
+
# # config/routes/third_party/some_gem.rb
|
1615
|
+
# mount SomeGem::Engine, at: "/some_gem"
|
1616
|
+
#
|
1617
|
+
# <b>CAUTION:</b> Use this feature with care. Having multiple routes
|
1618
|
+
# files can negatively impact discoverability and readability. For most
|
1619
|
+
# applications — even those with a few hundred routes — it's easier for
|
1620
|
+
# developers to have a single routes file.
|
1587
1621
|
def draw(name)
|
1588
1622
|
path = @draw_paths.find do |_path|
|
1589
1623
|
File.exist? "#{_path}/#{name}.rb"
|
@@ -1617,7 +1651,7 @@ module ActionDispatch
|
|
1617
1651
|
when Symbol
|
1618
1652
|
options[:action] = to
|
1619
1653
|
when String
|
1620
|
-
if
|
1654
|
+
if to.include?("#")
|
1621
1655
|
options[:to] = to
|
1622
1656
|
else
|
1623
1657
|
options[:controller] = to
|
@@ -1640,7 +1674,7 @@ module ActionDispatch
|
|
1640
1674
|
end
|
1641
1675
|
end
|
1642
1676
|
|
1643
|
-
# You can specify what Rails should route "/" to with the root method:
|
1677
|
+
# You can specify what \Rails should route "/" to with the root method:
|
1644
1678
|
#
|
1645
1679
|
# root to: 'pages#main'
|
1646
1680
|
#
|
@@ -1652,7 +1686,7 @@ module ActionDispatch
|
|
1652
1686
|
#
|
1653
1687
|
# You should put the root route at the top of <tt>config/routes.rb</tt>,
|
1654
1688
|
# because this means it will be matched first. As this is the most popular route
|
1655
|
-
# of most Rails applications, this is beneficial.
|
1689
|
+
# of most \Rails applications, this is beneficial.
|
1656
1690
|
def root(path, options = {})
|
1657
1691
|
if path.is_a?(String)
|
1658
1692
|
options[:to] = path
|
@@ -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.
|