actionpack 5.2.4.5 → 6.0.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 +111 -384
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/abstract_controller/base.rb +4 -2
- data/lib/abstract_controller/caching/fragments.rb +6 -21
- data/lib/abstract_controller/callbacks.rb +12 -0
- data/lib/abstract_controller/collector.rb +1 -1
- data/lib/abstract_controller/helpers.rb +2 -2
- data/lib/abstract_controller/railties/routes_helpers.rb +1 -1
- data/lib/action_controller.rb +1 -0
- data/lib/action_controller/api.rb +2 -1
- data/lib/action_controller/base.rb +2 -7
- data/lib/action_controller/caching.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +8 -5
- data/lib/action_controller/metal.rb +2 -2
- data/lib/action_controller/metal/conditional_get.rb +9 -3
- data/lib/action_controller/metal/data_streaming.rb +5 -6
- data/lib/action_controller/metal/default_headers.rb +17 -0
- data/lib/action_controller/metal/exceptions.rb +22 -1
- data/lib/action_controller/metal/flash.rb +5 -5
- data/lib/action_controller/metal/force_ssl.rb +17 -57
- data/lib/action_controller/metal/head.rb +1 -1
- data/lib/action_controller/metal/helpers.rb +1 -2
- data/lib/action_controller/metal/http_authentication.rb +20 -21
- data/lib/action_controller/metal/implicit_render.rb +2 -12
- data/lib/action_controller/metal/instrumentation.rb +3 -5
- data/lib/action_controller/metal/live.rb +28 -26
- data/lib/action_controller/metal/mime_responds.rb +13 -2
- data/lib/action_controller/metal/params_wrapper.rb +18 -14
- data/lib/action_controller/metal/redirecting.rb +32 -11
- data/lib/action_controller/metal/rendering.rb +1 -1
- data/lib/action_controller/metal/request_forgery_protection.rb +26 -40
- data/lib/action_controller/metal/strong_parameters.rb +57 -34
- data/lib/action_controller/metal/url_for.rb +1 -1
- data/lib/action_controller/railties/helpers.rb +1 -1
- data/lib/action_controller/renderer.rb +15 -2
- data/lib/action_controller/test_case.rb +3 -7
- data/lib/action_dispatch.rb +7 -6
- data/lib/action_dispatch/http/cache.rb +14 -10
- data/lib/action_dispatch/http/content_disposition.rb +45 -0
- data/lib/action_dispatch/http/content_security_policy.rb +9 -8
- data/lib/action_dispatch/http/filter_parameters.rb +8 -6
- data/lib/action_dispatch/http/filter_redirect.rb +1 -1
- data/lib/action_dispatch/http/headers.rb +1 -1
- data/lib/action_dispatch/http/mime_negotiation.rb +7 -10
- data/lib/action_dispatch/http/mime_type.rb +1 -5
- data/lib/action_dispatch/http/parameter_filter.rb +5 -79
- data/lib/action_dispatch/http/parameters.rb +13 -3
- data/lib/action_dispatch/http/request.rb +10 -13
- data/lib/action_dispatch/http/response.rb +14 -14
- data/lib/action_dispatch/http/upload.rb +5 -0
- data/lib/action_dispatch/http/url.rb +81 -81
- data/lib/action_dispatch/journey/formatter.rb +1 -1
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -2
- data/lib/action_dispatch/journey/nodes/node.rb +9 -8
- data/lib/action_dispatch/journey/path/pattern.rb +3 -4
- data/lib/action_dispatch/journey/router.rb +0 -3
- data/lib/action_dispatch/journey/router/utils.rb +10 -10
- data/lib/action_dispatch/journey/scanner.rb +11 -4
- data/lib/action_dispatch/journey/visitors.rb +1 -1
- data/lib/action_dispatch/middleware/callbacks.rb +2 -4
- data/lib/action_dispatch/middleware/cookies.rb +49 -70
- data/lib/action_dispatch/middleware/debug_exceptions.rb +32 -58
- data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
- data/lib/action_dispatch/middleware/debug_view.rb +50 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +36 -7
- data/lib/action_dispatch/middleware/flash.rb +1 -1
- data/lib/action_dispatch/middleware/host_authorization.rb +103 -0
- data/lib/action_dispatch/middleware/remote_ip.rb +6 -8
- data/lib/action_dispatch/middleware/request_id.rb +2 -2
- data/lib/action_dispatch/middleware/session/abstract_store.rb +0 -14
- data/lib/action_dispatch/middleware/session/cache_store.rb +6 -11
- data/lib/action_dispatch/middleware/session/cookie_store.rb +11 -27
- data/lib/action_dispatch/middleware/ssl.rb +8 -8
- data/lib/action_dispatch/middleware/stack.rb +2 -2
- data/lib/action_dispatch/middleware/static.rb +5 -6
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +20 -2
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +3 -0
- data/lib/action_dispatch/railtie.rb +1 -0
- data/lib/action_dispatch/request/session.rb +8 -6
- data/lib/action_dispatch/routing.rb +3 -2
- data/lib/action_dispatch/routing/inspector.rb +99 -50
- data/lib/action_dispatch/routing/mapper.rb +36 -29
- data/lib/action_dispatch/routing/polymorphic_routes.rb +3 -4
- data/lib/action_dispatch/routing/route_set.rb +11 -12
- data/lib/action_dispatch/routing/url_for.rb +1 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +3 -3
- data/lib/action_dispatch/testing/assertions/response.rb +2 -3
- data/lib/action_dispatch/testing/assertions/routing.rb +7 -2
- data/lib/action_dispatch/testing/integration.rb +11 -4
- data/lib/action_dispatch/testing/test_process.rb +2 -2
- data/lib/action_dispatch/testing/test_response.rb +4 -32
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/gem_version.rb +4 -4
- metadata +22 -20
@@ -83,7 +83,7 @@ module ActionDispatch
|
|
83
83
|
|
84
84
|
private
|
85
85
|
def set_hsts_header!(headers)
|
86
|
-
headers["Strict-Transport-Security"
|
86
|
+
headers["Strict-Transport-Security"] ||= @hsts_header
|
87
87
|
end
|
88
88
|
|
89
89
|
def normalize_hsts_options(options)
|
@@ -102,23 +102,23 @@ module ActionDispatch
|
|
102
102
|
|
103
103
|
# https://tools.ietf.org/html/rfc6797#section-6.1
|
104
104
|
def build_hsts_header(hsts)
|
105
|
-
value = "max-age=#{hsts[:expires].to_i}"
|
105
|
+
value = +"max-age=#{hsts[:expires].to_i}"
|
106
106
|
value << "; includeSubDomains" if hsts[:subdomains]
|
107
107
|
value << "; preload" if hsts[:preload]
|
108
108
|
value
|
109
109
|
end
|
110
110
|
|
111
111
|
def flag_cookies_as_secure!(headers)
|
112
|
-
if cookies = headers["Set-Cookie"
|
113
|
-
cookies = cookies.split("\n"
|
112
|
+
if cookies = headers["Set-Cookie"]
|
113
|
+
cookies = cookies.split("\n")
|
114
114
|
|
115
|
-
headers["Set-Cookie"
|
116
|
-
if
|
115
|
+
headers["Set-Cookie"] = cookies.map { |cookie|
|
116
|
+
if !/;\s*secure\s*(;|$)/i.match?(cookie)
|
117
117
|
"#{cookie}; secure"
|
118
118
|
else
|
119
119
|
cookie
|
120
120
|
end
|
121
|
-
}.join("\n"
|
121
|
+
}.join("\n")
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
@@ -141,7 +141,7 @@ module ActionDispatch
|
|
141
141
|
host = @redirect[:host] || request.host
|
142
142
|
port = @redirect[:port] || request.port
|
143
143
|
|
144
|
-
location = "https://#{host}"
|
144
|
+
location = +"https://#{host}"
|
145
145
|
location << ":#{port}" if port != 80 && port != 443
|
146
146
|
location << request.fullpath
|
147
147
|
location
|
@@ -97,8 +97,8 @@ module ActionDispatch
|
|
97
97
|
middlewares.push(build_middleware(klass, args, block))
|
98
98
|
end
|
99
99
|
|
100
|
-
def build(app =
|
101
|
-
middlewares.freeze.reverse.inject(app
|
100
|
+
def build(app = Proc.new)
|
101
|
+
middlewares.freeze.reverse.inject(app) { |a, e| e.build(a) }
|
102
102
|
end
|
103
103
|
|
104
104
|
private
|
@@ -41,7 +41,6 @@ module ActionDispatch
|
|
41
41
|
rescue SystemCallError
|
42
42
|
false
|
43
43
|
end
|
44
|
-
|
45
44
|
}
|
46
45
|
return ::Rack::Utils.escape_path(match).b
|
47
46
|
end
|
@@ -69,7 +68,7 @@ module ActionDispatch
|
|
69
68
|
|
70
69
|
headers["Vary"] = "Accept-Encoding" if gzip_path
|
71
70
|
|
72
|
-
|
71
|
+
[status, headers, body]
|
73
72
|
ensure
|
74
73
|
request.path_info = path
|
75
74
|
end
|
@@ -80,7 +79,7 @@ module ActionDispatch
|
|
80
79
|
end
|
81
80
|
|
82
81
|
def content_type(path)
|
83
|
-
::Rack::Mime.mime_type(::File.extname(path), "text/plain"
|
82
|
+
::Rack::Mime.mime_type(::File.extname(path), "text/plain")
|
84
83
|
end
|
85
84
|
|
86
85
|
def gzip_encoding_accepted?(request)
|
@@ -90,8 +89,8 @@ module ActionDispatch
|
|
90
89
|
def gzip_file_path(path)
|
91
90
|
can_gzip_mime = content_type(path) =~ /\A(?:text\/|application\/javascript)/
|
92
91
|
gzip_path = "#{path}.gz"
|
93
|
-
if can_gzip_mime && File.exist?(File.join(@root, ::Rack::Utils.unescape_path(gzip_path)
|
94
|
-
gzip_path
|
92
|
+
if can_gzip_mime && File.exist?(File.join(@root, ::Rack::Utils.unescape_path(gzip_path)))
|
93
|
+
gzip_path
|
95
94
|
else
|
96
95
|
false
|
97
96
|
end
|
@@ -117,7 +116,7 @@ module ActionDispatch
|
|
117
116
|
req = Rack::Request.new env
|
118
117
|
|
119
118
|
if req.get? || req.head?
|
120
|
-
path = req.path_info.chomp("/"
|
119
|
+
path = req.path_info.chomp("/")
|
121
120
|
if match = @file_handler.match?(path)
|
122
121
|
req.path_info = match
|
123
122
|
return @file_handler.serve(req)
|
@@ -1,6 +1,8 @@
|
|
1
|
-
<%
|
1
|
+
<% error_index = local_assigns[:error_index] || 0 %>
|
2
|
+
|
3
|
+
<% source_extracts.each_with_index do |source_extract, index| %>
|
2
4
|
<% if source_extract[:code] %>
|
3
|
-
<div class="source <%="hidden" if
|
5
|
+
<div class="source <%= "hidden" if show_source_idx != index %>" id="frame-source-<%= error_index %>-<%= index %>">
|
4
6
|
<div class="info">
|
5
7
|
Extracted source (around line <strong>#<%= source_extract[:line_number] %></strong>):
|
6
8
|
</div>
|
@@ -1,52 +1,62 @@
|
|
1
|
-
<% names =
|
1
|
+
<% names = traces.keys %>
|
2
|
+
<% error_index = local_assigns[:error_index] || 0 %>
|
2
3
|
|
3
4
|
<p><code>Rails.root: <%= defined?(Rails) && Rails.respond_to?(:root) ? Rails.root : "unset" %></code></p>
|
4
5
|
|
5
|
-
<div id="traces">
|
6
|
+
<div id="traces-<%= error_index %>">
|
6
7
|
<% names.each do |name| %>
|
7
8
|
<%
|
8
|
-
show = "show('#{name.gsub(/\s/, '-')}');"
|
9
|
-
hide = (names - [name]).collect {|hide_name| "hide('#{hide_name.gsub(/\s/, '-')}');"}
|
9
|
+
show = "show('#{name.gsub(/\s/, '-')}-#{error_index}');"
|
10
|
+
hide = (names - [name]).collect {|hide_name| "hide('#{hide_name.gsub(/\s/, '-')}-#{error_index}');"}
|
10
11
|
%>
|
11
12
|
<a href="#" onclick="<%= hide.join %><%= show %>; return false;"><%= name %></a> <%= '|' unless names.last == name %>
|
12
13
|
<% end %>
|
13
14
|
|
14
|
-
<%
|
15
|
-
<div id="<%= name.gsub(/\s/, '-') %>" style="display: <%= (name ==
|
16
|
-
<
|
15
|
+
<% traces.each do |name, trace| %>
|
16
|
+
<div id="<%= "#{name.gsub(/\s/, '-')}-#{error_index}" %>" style="display: <%= (name == trace_to_show) ? 'block' : 'none' %>;">
|
17
|
+
<code style="font-size: 11px;">
|
18
|
+
<% trace.each do |frame| %>
|
19
|
+
<a class="trace-frames trace-frames-<%= error_index %>" data-exception-object-id="<%= frame[:exception_object_id] %>" data-frame-id="<%= frame[:id] %>" href="#">
|
20
|
+
<%= frame[:trace] %>
|
21
|
+
</a>
|
22
|
+
<br>
|
23
|
+
<% end %>
|
24
|
+
</code>
|
17
25
|
</div>
|
18
26
|
<% end %>
|
19
27
|
|
20
28
|
<script type="text/javascript">
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
traceFrames
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
currentSource
|
46
|
-
|
47
|
-
|
29
|
+
(function() {
|
30
|
+
var traceFrames = document.getElementsByClassName('trace-frames-<%= error_index %>');
|
31
|
+
var selectedFrame, currentSource = document.getElementById('frame-source-<%= error_index %>-0');
|
32
|
+
|
33
|
+
// Add click listeners for all stack frames
|
34
|
+
for (var i = 0; i < traceFrames.length; i++) {
|
35
|
+
traceFrames[i].addEventListener('click', function(e) {
|
36
|
+
e.preventDefault();
|
37
|
+
var target = e.target;
|
38
|
+
var frame_id = target.dataset.frameId;
|
39
|
+
|
40
|
+
if (selectedFrame) {
|
41
|
+
selectedFrame.className = selectedFrame.className.replace("selected", "");
|
42
|
+
}
|
43
|
+
|
44
|
+
target.className += " selected";
|
45
|
+
selectedFrame = target;
|
46
|
+
|
47
|
+
// Change the extracted source code
|
48
|
+
changeSourceExtract(frame_id);
|
49
|
+
});
|
50
|
+
|
51
|
+
function changeSourceExtract(frame_id) {
|
52
|
+
var el = document.getElementById('frame-source-<%= error_index %>-' + frame_id);
|
53
|
+
if (currentSource && el) {
|
54
|
+
currentSource.className += " hidden";
|
55
|
+
el.className = el.className.replace(" hidden", "");
|
56
|
+
currentSource = el;
|
57
|
+
}
|
48
58
|
}
|
49
59
|
}
|
50
|
-
}
|
60
|
+
})();
|
51
61
|
</script>
|
52
62
|
</div>
|
@@ -10,7 +10,25 @@
|
|
10
10
|
<div id="container">
|
11
11
|
<h2><%= h @exception.message %></h2>
|
12
12
|
|
13
|
-
<%= render
|
14
|
-
<%= render
|
13
|
+
<%= render "rescues/source", source_extracts: @source_extracts, show_source_idx: @show_source_idx, error_index: 0 %>
|
14
|
+
<%= render "rescues/trace", traces: @traces, trace_to_show: @trace_to_show, error_index: 0 %>
|
15
|
+
|
16
|
+
<% if @exception.cause %>
|
17
|
+
<h2>Exception Causes</h2>
|
18
|
+
<% end %>
|
19
|
+
|
20
|
+
<% @exception_wrapper.wrapped_causes.each.with_index(1) do |wrapper, index| %>
|
21
|
+
<div class="details">
|
22
|
+
<a class="summary" href="#" style="color: #F0F0F0; text-decoration: none; background: #C52F24; border-bottom: none;" onclick="return toggle(<%= wrapper.exception.object_id %>)">
|
23
|
+
<%= wrapper.exception.class.name %>: <%= h wrapper.exception.message %>
|
24
|
+
</a>
|
25
|
+
</div>
|
26
|
+
|
27
|
+
<div id="<%= wrapper.exception.object_id %>" style="display: none;">
|
28
|
+
<%= render "rescues/source", source_extracts: wrapper.source_extracts, show_source_idx: wrapper.source_to_show_id, error_index: index %>
|
29
|
+
<%= render "rescues/trace", traces: wrapper.traces, trace_to_show: wrapper.trace_to_show, error_index: index %>
|
30
|
+
</div>
|
31
|
+
<% end %>
|
32
|
+
|
15
33
|
<%= render template: "rescues/_request_and_response" %>
|
16
34
|
</div>
|
@@ -10,12 +10,12 @@
|
|
10
10
|
<div id="container">
|
11
11
|
<h2>
|
12
12
|
<%= h @exception.message %>
|
13
|
-
<% if %r{#{ActiveStorage::Blob.table_name}|#{ActiveStorage::Attachment.table_name}}
|
14
|
-
<br />To resolve this issue run:
|
13
|
+
<% if @exception.message.match? %r{#{ActiveStorage::Blob.table_name}|#{ActiveStorage::Attachment.table_name}} %>
|
14
|
+
<br />To resolve this issue run: rails active_storage:install
|
15
15
|
<% end %>
|
16
16
|
</h2>
|
17
17
|
|
18
|
-
<%= render
|
19
|
-
<%= render
|
18
|
+
<%= render "rescues/source", source_extracts: @source_extracts, show_source_idx: @show_source_idx %>
|
19
|
+
<%= render "rescues/trace", traces: @traces, trace_to_show: @trace_to_show %>
|
20
20
|
<%= render template: "rescues/_request_and_response" %>
|
21
21
|
</div>
|
@@ -4,8 +4,8 @@
|
|
4
4
|
<% end %>
|
5
5
|
|
6
6
|
<%= @exception.message %>
|
7
|
-
<% if %r{#{ActiveStorage::Blob.table_name}|#{ActiveStorage::Attachment.table_name}}
|
8
|
-
To resolve this issue run:
|
7
|
+
<% if @exception.message.match? %r{#{ActiveStorage::Blob.table_name}|#{ActiveStorage::Attachment.table_name}} %>
|
8
|
+
To resolve this issue run: rails active_storage:install
|
9
9
|
<% end %>
|
10
10
|
|
11
11
|
<%= render template: "rescues/_source" %>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<header>
|
2
|
+
<h1>No template for interactive request</h1>
|
3
|
+
</header>
|
4
|
+
|
5
|
+
<div id="container">
|
6
|
+
<h2><%= h @exception.message %></h2>
|
7
|
+
|
8
|
+
<p class="summary">
|
9
|
+
<strong>NOTE!</strong><br>
|
10
|
+
Unless told otherwise, Rails expects an action to render a template with the same name,<br>
|
11
|
+
contained in a folder named after its controller.
|
12
|
+
|
13
|
+
If this controller is an API responding with 204 (No Content), <br>
|
14
|
+
which does not require a template,
|
15
|
+
then this error will occur when trying to access it via browser,<br>
|
16
|
+
since we expect an HTML template
|
17
|
+
to be rendered for such requests. If that's the case, carry on.
|
18
|
+
</p>
|
19
|
+
</div>
|
@@ -5,7 +5,7 @@
|
|
5
5
|
<div id="container">
|
6
6
|
<h2><%= h @exception.message %></h2>
|
7
7
|
|
8
|
-
<%= render
|
9
|
-
<%= render
|
8
|
+
<%= render "rescues/source", source_extracts: @source_extracts, show_source_idx: @show_source_idx %>
|
9
|
+
<%= render "rescues/trace", traces: @traces, trace_to_show: @trace_to_show %>
|
10
10
|
<%= render template: "rescues/_request_and_response" %>
|
11
11
|
</div>
|
@@ -11,10 +11,10 @@
|
|
11
11
|
</p>
|
12
12
|
<pre><code><%= h @exception.message %></code></pre>
|
13
13
|
|
14
|
-
<%= render
|
14
|
+
<%= render "rescues/source", source_extracts: @source_extracts, show_source_idx: @show_source_idx %>
|
15
15
|
|
16
16
|
<p><%= @exception.sub_template_message %></p>
|
17
17
|
|
18
|
-
<%= render
|
18
|
+
<%= render "rescues/trace", traces: @traces, trace_to_show: @trace_to_show %>
|
19
19
|
<%= render template: "rescues/_request_and_response" %>
|
20
20
|
</div>
|
@@ -21,6 +21,7 @@ module ActionDispatch
|
|
21
21
|
config.action_dispatch.encrypted_signed_cookie_salt = "signed encrypted cookie"
|
22
22
|
config.action_dispatch.authenticated_encrypted_cookie_salt = "authenticated encrypted cookie"
|
23
23
|
config.action_dispatch.use_authenticated_cookie_encryption = false
|
24
|
+
config.action_dispatch.use_cookies_with_metadata = false
|
24
25
|
config.action_dispatch.perform_deep_munge = true
|
25
26
|
|
26
27
|
config.action_dispatch.default_headers = {
|
@@ -90,13 +90,15 @@ module ActionDispatch
|
|
90
90
|
# +nil+ if the given key is not found in the session.
|
91
91
|
def [](key)
|
92
92
|
load_for_read!
|
93
|
-
key
|
93
|
+
@delegate[key.to_s]
|
94
|
+
end
|
94
95
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
96
|
+
# Returns the nested value specified by the sequence of keys, returning
|
97
|
+
# +nil+ if any intermediate step is +nil+.
|
98
|
+
def dig(*keys)
|
99
|
+
load_for_read!
|
100
|
+
keys = keys.map.with_index { |key, i| i.zero? ? key.to_s : key }
|
101
|
+
@delegate.dig(*keys)
|
100
102
|
end
|
101
103
|
|
102
104
|
# Returns true if the session has the given key or false.
|
@@ -243,8 +243,9 @@ module ActionDispatch
|
|
243
243
|
#
|
244
244
|
# rails routes
|
245
245
|
#
|
246
|
-
# Target specific
|
247
|
-
#
|
246
|
+
# Target a specific controller with <tt>-c</tt>, or grep routes
|
247
|
+
# using <tt>-g</tt>. Useful in conjunction with <tt>--expanded</tt>
|
248
|
+
# which displays routes vertically.
|
248
249
|
module Routing
|
249
250
|
extend ActiveSupport::Autoload
|
250
251
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "delegate"
|
4
|
-
require "
|
4
|
+
require "io/console/size"
|
5
5
|
|
6
6
|
module ActionDispatch
|
7
7
|
module Routing
|
@@ -61,11 +61,11 @@ module ActionDispatch
|
|
61
61
|
@routes = routes
|
62
62
|
end
|
63
63
|
|
64
|
-
def format(formatter, filter =
|
64
|
+
def format(formatter, filter = {})
|
65
65
|
routes_to_display = filter_routes(normalize_filter(filter))
|
66
66
|
routes = collect_routes(routes_to_display)
|
67
67
|
if routes.none?
|
68
|
-
formatter.no_routes(collect_routes(@routes))
|
68
|
+
formatter.no_routes(collect_routes(@routes), filter)
|
69
69
|
return formatter.result
|
70
70
|
end
|
71
71
|
|
@@ -81,12 +81,12 @@ module ActionDispatch
|
|
81
81
|
end
|
82
82
|
|
83
83
|
private
|
84
|
-
|
85
84
|
def normalize_filter(filter)
|
86
|
-
if filter
|
85
|
+
if filter[:controller]
|
87
86
|
{ controller: /#{filter[:controller].underscore.sub(/_?controller\z/, "")}/ }
|
88
|
-
elsif filter
|
89
|
-
{ controller: /#{filter}/, action: /#{filter
|
87
|
+
elsif filter[:grep]
|
88
|
+
{ controller: /#{filter[:grep]}/, action: /#{filter[:grep]}/,
|
89
|
+
verb: /#{filter[:grep]}/, name: /#{filter[:grep]}/, path: /#{filter[:grep]}/ }
|
90
90
|
end
|
91
91
|
end
|
92
92
|
|
@@ -126,62 +126,111 @@ module ActionDispatch
|
|
126
126
|
end
|
127
127
|
end
|
128
128
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
129
|
+
module ConsoleFormatter
|
130
|
+
class Base
|
131
|
+
def initialize
|
132
|
+
@buffer = []
|
133
|
+
end
|
133
134
|
|
134
|
-
|
135
|
-
|
136
|
-
|
135
|
+
def result
|
136
|
+
@buffer.join("\n")
|
137
|
+
end
|
137
138
|
|
138
|
-
|
139
|
-
|
140
|
-
end
|
139
|
+
def section_title(title)
|
140
|
+
end
|
141
141
|
|
142
|
-
|
143
|
-
|
144
|
-
end
|
142
|
+
def section(routes)
|
143
|
+
end
|
145
144
|
|
146
|
-
|
147
|
-
|
148
|
-
end
|
145
|
+
def header(routes)
|
146
|
+
end
|
149
147
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
148
|
+
def no_routes(routes, filter)
|
149
|
+
@buffer <<
|
150
|
+
if routes.none?
|
151
|
+
<<~MESSAGE
|
152
|
+
You don't have any routes defined!
|
153
|
+
|
154
|
+
Please add some routes in config/routes.rb.
|
155
|
+
MESSAGE
|
156
|
+
elsif filter.key?(:controller)
|
157
|
+
"No routes were found for this controller."
|
158
|
+
elsif filter.key?(:grep)
|
159
|
+
"No routes were found for this grep pattern."
|
160
|
+
end
|
155
161
|
|
156
|
-
|
157
|
-
MESSAGE
|
158
|
-
else
|
159
|
-
"No routes were found for this controller"
|
162
|
+
@buffer << "For more information about routes, see the Rails guide: https://guides.rubyonrails.org/routing.html."
|
160
163
|
end
|
161
|
-
@buffer << "For more information about routes, see the Rails guide: http://guides.rubyonrails.org/routing.html."
|
162
164
|
end
|
163
165
|
|
164
|
-
|
165
|
-
def
|
166
|
-
|
167
|
-
|
166
|
+
class Sheet < Base
|
167
|
+
def section_title(title)
|
168
|
+
@buffer << "\n#{title}:"
|
169
|
+
end
|
168
170
|
|
169
|
-
|
170
|
-
|
171
|
-
|
171
|
+
def section(routes)
|
172
|
+
@buffer << draw_section(routes)
|
173
|
+
end
|
174
|
+
|
175
|
+
def header(routes)
|
176
|
+
@buffer << draw_header(routes)
|
172
177
|
end
|
173
178
|
|
174
|
-
|
175
|
-
|
179
|
+
private
|
180
|
+
|
181
|
+
def draw_section(routes)
|
182
|
+
header_lengths = ["Prefix", "Verb", "URI Pattern"].map(&:length)
|
183
|
+
name_width, verb_width, path_width = widths(routes).zip(header_lengths).map(&:max)
|
184
|
+
|
185
|
+
routes.map do |r|
|
186
|
+
"#{r[:name].rjust(name_width)} #{r[:verb].ljust(verb_width)} #{r[:path].ljust(path_width)} #{r[:reqs]}"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def draw_header(routes)
|
191
|
+
name_width, verb_width, path_width = widths(routes)
|
192
|
+
|
193
|
+
"#{"Prefix".rjust(name_width)} #{"Verb".ljust(verb_width)} #{"URI Pattern".ljust(path_width)} Controller#Action"
|
194
|
+
end
|
195
|
+
|
196
|
+
def widths(routes)
|
197
|
+
[routes.map { |r| r[:name].length }.max || 0,
|
198
|
+
routes.map { |r| r[:verb].length }.max || 0,
|
199
|
+
routes.map { |r| r[:path].length }.max || 0]
|
200
|
+
end
|
201
|
+
end
|
176
202
|
|
177
|
-
|
203
|
+
class Expanded < Base
|
204
|
+
def section_title(title)
|
205
|
+
@buffer << "\n#{"[ #{title} ]"}"
|
178
206
|
end
|
179
207
|
|
180
|
-
def
|
181
|
-
|
182
|
-
routes.map { |r| r[:verb].length }.max || 0,
|
183
|
-
routes.map { |r| r[:path].length }.max || 0]
|
208
|
+
def section(routes)
|
209
|
+
@buffer << draw_expanded_section(routes)
|
184
210
|
end
|
211
|
+
|
212
|
+
private
|
213
|
+
|
214
|
+
def draw_expanded_section(routes)
|
215
|
+
routes.map.each_with_index do |r, i|
|
216
|
+
<<~MESSAGE.chomp
|
217
|
+
#{route_header(index: i + 1)}
|
218
|
+
Prefix | #{r[:name]}
|
219
|
+
Verb | #{r[:verb]}
|
220
|
+
URI | #{r[:path]}
|
221
|
+
Controller#Action | #{r[:reqs]}
|
222
|
+
MESSAGE
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def route_header(index:)
|
227
|
+
console_width = IO.console_size.second
|
228
|
+
header_prefix = "--[ Route #{index} ]"
|
229
|
+
dash_remainder = [console_width - header_prefix.size, 0].max
|
230
|
+
|
231
|
+
"#{header_prefix}#{'-' * dash_remainder}"
|
232
|
+
end
|
233
|
+
end
|
185
234
|
end
|
186
235
|
|
187
236
|
class HtmlTableFormatter
|
@@ -203,16 +252,16 @@ module ActionDispatch
|
|
203
252
|
end
|
204
253
|
|
205
254
|
def no_routes(*)
|
206
|
-
@buffer <<
|
255
|
+
@buffer << <<~MESSAGE
|
207
256
|
<p>You don't have any routes defined!</p>
|
208
257
|
<ul>
|
209
258
|
<li>Please add some routes in <tt>config/routes.rb</tt>.</li>
|
210
259
|
<li>
|
211
260
|
For more information about routes, please see the Rails guide
|
212
|
-
<a href="
|
261
|
+
<a href="https://guides.rubyonrails.org/routing.html">Rails Routing from the Outside In</a>.
|
213
262
|
</li>
|
214
263
|
</ul>
|
215
|
-
|
264
|
+
MESSAGE
|
216
265
|
end
|
217
266
|
|
218
267
|
def result
|