actionpack 7.0.8.6 → 7.1.0.beta1
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 +318 -423
- data/MIT-LICENSE +1 -1
- data/README.rdoc +2 -2
- data/lib/abstract_controller/base.rb +19 -10
- 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 +61 -18
- data/lib/abstract_controller/railties/routes_helpers.rb +1 -16
- data/lib/abstract_controller/rendering.rb +3 -3
- data/lib/abstract_controller/translation.rb +1 -27
- data/lib/abstract_controller/url_for.rb +2 -0
- data/lib/abstract_controller.rb +6 -0
- data/lib/action_controller/api.rb +5 -3
- 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/content_security_policy.rb +1 -1
- data/lib/action_controller/metal/data_streaming.rb +2 -0
- data/lib/action_controller/metal/default_headers.rb +2 -0
- data/lib/action_controller/metal/etag_with_flash.rb +2 -0
- 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 +8 -6
- data/lib/action_controller/metal/helpers.rb +3 -14
- data/lib/action_controller/metal/http_authentication.rb +10 -4
- 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 +24 -0
- data/lib/action_controller/metal/mime_responds.rb +2 -2
- data/lib/action_controller/metal/params_wrapper.rb +3 -1
- data/lib/action_controller/metal/permissions_policy.rb +1 -1
- data/lib/action_controller/metal/redirecting.rb +6 -6
- data/lib/action_controller/metal/renderers.rb +2 -2
- data/lib/action_controller/metal/rendering.rb +0 -7
- data/lib/action_controller/metal/request_forgery_protection.rb +138 -50
- data/lib/action_controller/metal/rescue.rb +2 -0
- data/lib/action_controller/metal/streaming.rb +70 -30
- data/lib/action_controller/metal/strong_parameters.rb +89 -50
- data/lib/action_controller/metal/url_for.rb +7 -0
- data/lib/action_controller/metal.rb +79 -21
- data/lib/action_controller/railtie.rb +22 -9
- data/lib/action_controller/renderer.rb +98 -65
- 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 +1 -3
- data/lib/action_dispatch/http/content_security_policy.rb +9 -8
- data/lib/action_dispatch/http/filter_parameters.rb +15 -14
- data/lib/action_dispatch/http/headers.rb +2 -0
- data/lib/action_dispatch/http/mime_negotiation.rb +21 -21
- 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 +44 -15
- data/lib/action_dispatch/http/rack_cache.rb +2 -0
- data/lib/action_dispatch/http/request.rb +48 -14
- data/lib/action_dispatch/http/response.rb +78 -59
- data/lib/action_dispatch/http/upload.rb +2 -0
- 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 +5 -4
- 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 +81 -98
- 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 +181 -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 +6 -3
- 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 +17 -16
- data/lib/action_dispatch/middleware/request_id.rb +2 -0
- 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 +19 -15
- 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 +12 -8
- 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/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 +46 -37
- 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 +26 -14
- 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 +1 -1
- data/lib/action_dispatch/routing/url_for.rb +5 -1
- data/lib/action_dispatch/routing.rb +4 -4
- data/lib/action_dispatch/system_test_case.rb +3 -3
- data/lib/action_dispatch/system_testing/browser.rb +5 -6
- data/lib/action_dispatch/system_testing/driver.rb +13 -21
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +27 -16
- data/lib/action_dispatch/testing/assertions/response.rb +13 -6
- 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 +55 -33
@@ -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,8 +109,8 @@
|
|
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
115
|
function checkNoMatch(section, trElement) {
|
106
116
|
if (section.children.length <= 1) {
|
@@ -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]'),
|
@@ -156,16 +166,16 @@
|
|
156
166
|
|
157
167
|
// On key press perform a search for matching paths
|
158
168
|
delayedKeyup(searchElem, function() {
|
159
|
-
var
|
160
|
-
defaultExactMatch = buildTr(
|
161
|
-
defaultFuzzyMatch = buildTr(
|
162
|
-
noExactMatch = buildTr('No
|
163
|
-
noFuzzyMatch = buildTr('No
|
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');
|
164
174
|
|
165
|
-
if (!
|
175
|
+
if (!query)
|
166
176
|
return searchElem.onblur();
|
167
177
|
|
168
|
-
getJSON('/rails/info/routes?
|
178
|
+
getJSON('/rails/info/routes?query=' + query, function(matches){
|
169
179
|
// Clear out results section
|
170
180
|
exactSection.replaceChildren(defaultExactMatch);
|
171
181
|
fuzzySection.replaceChildren(defaultFuzzyMatch);
|
@@ -173,7 +183,6 @@
|
|
173
183
|
// Display exact matches and fuzzy matches
|
174
184
|
pathElements.forEach(function(elem) {
|
175
185
|
var elemPath = elem.getAttribute('data-route-path');
|
176
|
-
|
177
186
|
if (matches['exact'].indexOf(elemPath) != -1)
|
178
187
|
exactSection.appendChild(elem.parentNode.cloneNode(true));
|
179
188
|
|
@@ -215,7 +224,7 @@
|
|
215
224
|
});
|
216
225
|
}
|
217
226
|
|
218
|
-
|
227
|
+
setupMatchingRoutes();
|
219
228
|
setupRouteToggleHelperLinks();
|
220
229
|
|
221
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
|
@@ -306,7 +309,7 @@ module ActionDispatch
|
|
306
309
|
end
|
307
310
|
|
308
311
|
def split_to(to)
|
309
|
-
if
|
312
|
+
if to&.include?("#")
|
310
313
|
to.split("#").map!(&:-@)
|
311
314
|
else
|
312
315
|
[]
|
@@ -356,6 +359,15 @@ module ActionDispatch
|
|
356
359
|
def dispatcher(raise_on_name_error)
|
357
360
|
Routing::RouteSet::Dispatcher.new raise_on_name_error
|
358
361
|
end
|
362
|
+
|
363
|
+
def route_source_location
|
364
|
+
if Mapper.route_source_locations
|
365
|
+
action_dispatch_dir = File.expand_path("..", __dir__)
|
366
|
+
caller_location = caller_locations.find { |location| !location.path.include?(action_dispatch_dir) }
|
367
|
+
cleaned_path = Mapper.backtrace_cleaner.clean([caller_location.path]).first
|
368
|
+
"#{cleaned_path}:#{caller_location.lineno}" if cleaned_path
|
369
|
+
end
|
370
|
+
end
|
359
371
|
end
|
360
372
|
|
361
373
|
# Invokes Journey::Router::Utils.normalize_path, then ensures that
|
@@ -652,7 +664,7 @@ module ActionDispatch
|
|
652
664
|
|
653
665
|
script_namer = ->(options) do
|
654
666
|
prefix_options = options.slice(*_route.segment_keys)
|
655
|
-
prefix_options[:
|
667
|
+
prefix_options[:script_name] = "" if options[:original_script_name]
|
656
668
|
|
657
669
|
if options[:_recall]
|
658
670
|
prefix_options.reverse_merge!(options[:_recall].slice(*_route.segment_keys))
|
@@ -748,7 +760,7 @@ module ActionDispatch
|
|
748
760
|
# end
|
749
761
|
#
|
750
762
|
# This will create a number of routes for each of the posts and comments
|
751
|
-
# controller. For
|
763
|
+
# controller. For +Admin::PostsController+, \Rails will create:
|
752
764
|
#
|
753
765
|
# GET /admin/posts
|
754
766
|
# GET /admin/posts/new
|
@@ -759,7 +771,7 @@ module ActionDispatch
|
|
759
771
|
# DELETE /admin/posts/1
|
760
772
|
#
|
761
773
|
# If you want to route /posts (without the prefix /admin) to
|
762
|
-
#
|
774
|
+
# +Admin::PostsController+, you could use
|
763
775
|
#
|
764
776
|
# scope module: "admin" do
|
765
777
|
# resources :posts
|
@@ -808,7 +820,7 @@ module ActionDispatch
|
|
808
820
|
#
|
809
821
|
# Takes same options as <tt>Base#match</tt> and <tt>Resources#resources</tt>.
|
810
822
|
#
|
811
|
-
# # route /posts (without the prefix /admin) to
|
823
|
+
# # route /posts (without the prefix /admin) to +Admin::PostsController+
|
812
824
|
# scope module: "admin" do
|
813
825
|
# resources :posts
|
814
826
|
# end
|
@@ -917,7 +929,7 @@ module ActionDispatch
|
|
917
929
|
# resources :posts
|
918
930
|
# end
|
919
931
|
#
|
920
|
-
# # maps to
|
932
|
+
# # maps to +Sekret::PostsController+ rather than +Admin::PostsController+
|
921
933
|
# namespace :admin, module: "sekret" do
|
922
934
|
# resources :posts
|
923
935
|
# end
|
@@ -1318,7 +1330,7 @@ module ActionDispatch
|
|
1318
1330
|
self
|
1319
1331
|
end
|
1320
1332
|
|
1321
|
-
# In Rails, a resourceful route provides a mapping between HTTP verbs
|
1333
|
+
# In \Rails, a resourceful route provides a mapping between HTTP verbs
|
1322
1334
|
# and URLs and controller actions. By convention, each action also maps
|
1323
1335
|
# to particular CRUD operations in a database. A single entry in the
|
1324
1336
|
# routing file, such as
|
@@ -1450,7 +1462,7 @@ module ActionDispatch
|
|
1450
1462
|
#
|
1451
1463
|
# === Examples
|
1452
1464
|
#
|
1453
|
-
# # routes call
|
1465
|
+
# # routes call +Admin::PostsController+
|
1454
1466
|
# resources :posts, module: "admin"
|
1455
1467
|
#
|
1456
1468
|
# # resource actions are at /admin/posts.
|
@@ -1493,7 +1505,7 @@ module ActionDispatch
|
|
1493
1505
|
# end
|
1494
1506
|
# end
|
1495
1507
|
#
|
1496
|
-
# This will enable Rails to recognize paths such as <tt>/photos/search</tt>
|
1508
|
+
# This will enable \Rails to recognize paths such as <tt>/photos/search</tt>
|
1497
1509
|
# with GET, and route to the search action of +PhotosController+. It will also
|
1498
1510
|
# create the <tt>search_photos_url</tt> and <tt>search_photos_path</tt>
|
1499
1511
|
# route helpers.
|
@@ -1640,7 +1652,7 @@ module ActionDispatch
|
|
1640
1652
|
when Symbol
|
1641
1653
|
options[:action] = to
|
1642
1654
|
when String
|
1643
|
-
if
|
1655
|
+
if to.include?("#")
|
1644
1656
|
options[:to] = to
|
1645
1657
|
else
|
1646
1658
|
options[:controller] = to
|
@@ -1663,7 +1675,7 @@ module ActionDispatch
|
|
1663
1675
|
end
|
1664
1676
|
end
|
1665
1677
|
|
1666
|
-
# You can specify what Rails should route "/" to with the root method:
|
1678
|
+
# You can specify what \Rails should route "/" to with the root method:
|
1667
1679
|
#
|
1668
1680
|
# root to: 'pages#main'
|
1669
1681
|
#
|
@@ -1675,7 +1687,7 @@ module ActionDispatch
|
|
1675
1687
|
#
|
1676
1688
|
# You should put the root route at the top of <tt>config/routes.rb</tt>,
|
1677
1689
|
# because this means it will be matched first. As this is the most popular route
|
1678
|
-
# of most Rails applications, this is beneficial.
|
1690
|
+
# of most \Rails applications, this is beneficial.
|
1679
1691
|
def root(path, options = {})
|
1680
1692
|
if path.is_a?(String)
|
1681
1693
|
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.
|
@@ -18,10 +18,19 @@ module ActionDispatch
|
|
18
18
|
def redirect?; true; end
|
19
19
|
|
20
20
|
def call(env)
|
21
|
-
|
21
|
+
ActiveSupport::Notifications.instrument("redirect.action_dispatch") do |payload|
|
22
|
+
request = Request.new(env)
|
23
|
+
response = build_response(request)
|
24
|
+
|
25
|
+
payload[:status] = @status
|
26
|
+
payload[:location] = response.headers["Location"]
|
27
|
+
payload[:request] = request
|
28
|
+
|
29
|
+
response.to_a
|
30
|
+
end
|
22
31
|
end
|
23
32
|
|
24
|
-
def
|
33
|
+
def build_response(req)
|
25
34
|
uri = URI.parse(path(req.path_parameters, req))
|
26
35
|
|
27
36
|
unless uri.host
|
@@ -38,15 +47,15 @@ module ActionDispatch
|
|
38
47
|
|
39
48
|
req.commit_flash
|
40
49
|
|
41
|
-
body =
|
50
|
+
body = ""
|
42
51
|
|
43
52
|
headers = {
|
44
53
|
"Location" => uri.to_s,
|
45
|
-
"Content-Type" => "text/html",
|
54
|
+
"Content-Type" => "text/html; charset=#{ActionDispatch::Response.default_charset}",
|
46
55
|
"Content-Length" => body.length.to_s
|
47
56
|
}
|
48
57
|
|
49
|
-
|
58
|
+
ActionDispatch::Response.new(status, headers, body)
|
50
59
|
end
|
51
60
|
|
52
61
|
def path(params, request)
|
@@ -59,7 +68,7 @@ module ActionDispatch
|
|
59
68
|
|
60
69
|
private
|
61
70
|
def relative_path?(path)
|
62
|
-
path && !path.empty? && path
|
71
|
+
path && !path.empty? && !path.start_with?("/")
|
63
72
|
end
|
64
73
|
|
65
74
|
def escape(params)
|