actionpack 5.2.8.1 → 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 +109 -482
- 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/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/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 +21 -22
- 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 +32 -97
- data/lib/action_controller/metal/strong_parameters.rb +57 -34
- data/lib/action_controller/metal/url_for.rb +1 -1
- data/lib/action_controller/metal.rb +2 -2
- data/lib/action_controller/railties/helpers.rb +1 -1
- data/lib/action_controller/renderer.rb +15 -2
- data/lib/action_controller/test_case.rb +5 -9
- data/lib/action_controller.rb +1 -0
- 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 +17 -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/utils.rb +10 -10
- data/lib/action_dispatch/journey/router.rb +0 -3
- 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/executor.rb +1 -1
- 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/inspector.rb +99 -50
- data/lib/action_dispatch/routing/mapper.rb +36 -29
- data/lib/action_dispatch/routing/polymorphic_routes.rb +7 -12
- data/lib/action_dispatch/routing/route_set.rb +11 -12
- data/lib/action_dispatch/routing/url_for.rb +1 -0
- data/lib/action_dispatch/routing.rb +3 -2
- 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 -5
- data/lib/action_dispatch/testing/test_process.rb +2 -2
- data/lib/action_dispatch/testing/test_response.rb +4 -32
- data/lib/action_dispatch.rb +7 -6
- data/lib/action_pack/gem_version.rb +4 -4
- data/lib/action_pack.rb +1 -1
- metadata +25 -23
@@ -162,14 +162,12 @@ module ActionDispatch
|
|
162
162
|
# Split the comma-separated list into an array of strings.
|
163
163
|
ips = header.strip.split(/[,\s]+/)
|
164
164
|
ips.select do |ip|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
nil
|
172
|
-
end
|
165
|
+
# Only return IPs that are valid according to the IPAddr#new method.
|
166
|
+
range = IPAddr.new(ip).to_range
|
167
|
+
# We want to make sure nobody is sneaking a netmask in.
|
168
|
+
range.begin == range.end
|
169
|
+
rescue ArgumentError
|
170
|
+
nil
|
173
171
|
end
|
174
172
|
end
|
175
173
|
|
@@ -15,7 +15,7 @@ module ActionDispatch
|
|
15
15
|
# The unique request id can be used to trace a request end-to-end and would typically end up being part of log files
|
16
16
|
# from multiple pieces of the stack.
|
17
17
|
class RequestId
|
18
|
-
X_REQUEST_ID = "X-Request-Id"
|
18
|
+
X_REQUEST_ID = "X-Request-Id" #:nodoc:
|
19
19
|
|
20
20
|
def initialize(app)
|
21
21
|
@app = app
|
@@ -30,7 +30,7 @@ module ActionDispatch
|
|
30
30
|
private
|
31
31
|
def make_request_id(request_id)
|
32
32
|
if request_id.presence
|
33
|
-
request_id.gsub(/[^\w\-@]/, ""
|
33
|
+
request_id.gsub(/[^\w\-@]/, "").first(255)
|
34
34
|
else
|
35
35
|
internal_request_id
|
36
36
|
end
|
@@ -83,21 +83,7 @@ module ActionDispatch
|
|
83
83
|
include SessionObject
|
84
84
|
|
85
85
|
private
|
86
|
-
def set_cookie(request, session_id, cookie)
|
87
|
-
request.cookie_jar[key] = cookie
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
class AbstractSecureStore < Rack::Session::Abstract::PersistedSecure
|
92
|
-
include Compatibility
|
93
|
-
include StaleSessionCheck
|
94
|
-
include SessionObject
|
95
|
-
|
96
|
-
def generate_sid
|
97
|
-
Rack::Session::SessionId.new(super)
|
98
|
-
end
|
99
86
|
|
100
|
-
private
|
101
87
|
def set_cookie(request, session_id, cookie)
|
102
88
|
request.cookie_jar[key] = cookie
|
103
89
|
end
|
@@ -12,7 +12,7 @@ module ActionDispatch
|
|
12
12
|
# * <tt>cache</tt> - The cache to use. If it is not specified, <tt>Rails.cache</tt> will be used.
|
13
13
|
# * <tt>expire_after</tt> - The length of time a session will be stored before automatically expiring.
|
14
14
|
# By default, the <tt>:expires_in</tt> option of the cache is used.
|
15
|
-
class CacheStore <
|
15
|
+
class CacheStore < AbstractStore
|
16
16
|
def initialize(app, options = {})
|
17
17
|
@cache = options[:cache] || Rails.cache
|
18
18
|
options[:expire_after] ||= @cache.options[:expires_in]
|
@@ -21,7 +21,7 @@ module ActionDispatch
|
|
21
21
|
|
22
22
|
# Get a session from the cache.
|
23
23
|
def find_session(env, sid)
|
24
|
-
unless sid && (session =
|
24
|
+
unless sid && (session = @cache.read(cache_key(sid)))
|
25
25
|
sid, session = generate_sid, {}
|
26
26
|
end
|
27
27
|
[sid, session]
|
@@ -29,7 +29,7 @@ module ActionDispatch
|
|
29
29
|
|
30
30
|
# Set a session in the cache.
|
31
31
|
def write_session(env, sid, session, options)
|
32
|
-
key = cache_key(sid
|
32
|
+
key = cache_key(sid)
|
33
33
|
if session
|
34
34
|
@cache.write(key, session, expires_in: options[:expire_after])
|
35
35
|
else
|
@@ -40,19 +40,14 @@ module ActionDispatch
|
|
40
40
|
|
41
41
|
# Remove a session from the cache.
|
42
42
|
def delete_session(env, sid, options)
|
43
|
-
@cache.delete(cache_key(sid
|
44
|
-
@cache.delete(cache_key(sid.public_id))
|
43
|
+
@cache.delete(cache_key(sid))
|
45
44
|
generate_sid
|
46
45
|
end
|
47
46
|
|
48
47
|
private
|
49
48
|
# Turn the session id into a cache key.
|
50
|
-
def cache_key(
|
51
|
-
"_session_id:#{
|
52
|
-
end
|
53
|
-
|
54
|
-
def get_session_with_fallback(sid)
|
55
|
-
@cache.read(cache_key(sid.private_id)) || @cache.read(cache_key(sid.public_id))
|
49
|
+
def cache_key(sid)
|
50
|
+
"_session_id:#{sid}"
|
56
51
|
end
|
57
52
|
end
|
58
53
|
end
|
@@ -16,23 +16,17 @@ module ActionDispatch
|
|
16
16
|
# The cookie jar used for storage is automatically configured to be the
|
17
17
|
# best possible option given your application's configuration.
|
18
18
|
#
|
19
|
-
# If you only have secret_token set, your cookies will be signed, but
|
20
|
-
# not encrypted. This means a user cannot alter their +user_id+ without
|
21
|
-
# knowing your app's secret key, but can easily read their +user_id+. This
|
22
|
-
# was the default for Rails 3 apps.
|
23
|
-
#
|
24
19
|
# Your cookies will be encrypted using your apps secret_key_base. This
|
25
20
|
# goes a step further than signed cookies in that encrypted cookies cannot
|
26
21
|
# be altered or read by users. This is the default starting in Rails 4.
|
27
22
|
#
|
28
|
-
# Configure your session store in
|
23
|
+
# Configure your session store in an initializer:
|
29
24
|
#
|
30
25
|
# Rails.application.config.session_store :cookie_store, key: '_your_app_session'
|
31
26
|
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
# <tt>config/credentials.yml.enc</tt> file.
|
27
|
+
# By default, your secret key base is derived from your application name in
|
28
|
+
# the test and development environments. In all other environments, it is stored
|
29
|
+
# encrypted in the <tt>config/credentials.yml.enc</tt> file.
|
36
30
|
#
|
37
31
|
# If your application was not updated to Rails 5.2 defaults, the secret_key_base
|
38
32
|
# will be found in the old <tt>config/secrets.yml</tt> file.
|
@@ -51,16 +45,7 @@ module ActionDispatch
|
|
51
45
|
# would set the session cookie to expire automatically 14 days after creation.
|
52
46
|
# Other useful options include <tt>:key</tt>, <tt>:secure</tt> and
|
53
47
|
# <tt>:httponly</tt>.
|
54
|
-
class CookieStore <
|
55
|
-
class SessionId < DelegateClass(Rack::Session::SessionId)
|
56
|
-
attr_reader :cookie_value
|
57
|
-
|
58
|
-
def initialize(session_id, cookie_value = {})
|
59
|
-
super(session_id)
|
60
|
-
@cookie_value = cookie_value
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
48
|
+
class CookieStore < AbstractStore
|
64
49
|
def initialize(app, options = {})
|
65
50
|
super(app, options.merge!(cookie_only: true))
|
66
51
|
end
|
@@ -68,7 +53,7 @@ module ActionDispatch
|
|
68
53
|
def delete_session(req, session_id, options)
|
69
54
|
new_sid = generate_sid unless options[:drop]
|
70
55
|
# Reset hash and Assign the new session id
|
71
|
-
req.set_header("action_dispatch.request.unsigned_session_cookie", new_sid ? { "session_id" => new_sid
|
56
|
+
req.set_header("action_dispatch.request.unsigned_session_cookie", new_sid ? { "session_id" => new_sid } : {})
|
72
57
|
new_sid
|
73
58
|
end
|
74
59
|
|
@@ -76,7 +61,7 @@ module ActionDispatch
|
|
76
61
|
stale_session_check! do
|
77
62
|
data = unpacked_cookie_data(req)
|
78
63
|
data = persistent_session_id!(data)
|
79
|
-
[
|
64
|
+
[data["session_id"], data]
|
80
65
|
end
|
81
66
|
end
|
82
67
|
|
@@ -84,8 +69,7 @@ module ActionDispatch
|
|
84
69
|
|
85
70
|
def extract_session_id(req)
|
86
71
|
stale_session_check! do
|
87
|
-
|
88
|
-
sid && Rack::Session::SessionId.new(sid)
|
72
|
+
unpacked_cookie_data(req)["session_id"]
|
89
73
|
end
|
90
74
|
end
|
91
75
|
|
@@ -103,13 +87,13 @@ module ActionDispatch
|
|
103
87
|
|
104
88
|
def persistent_session_id!(data, sid = nil)
|
105
89
|
data ||= {}
|
106
|
-
data["session_id"] ||= sid || generate_sid
|
90
|
+
data["session_id"] ||= sid || generate_sid
|
107
91
|
data
|
108
92
|
end
|
109
93
|
|
110
94
|
def write_session(req, sid, session_data, options)
|
111
|
-
session_data["session_id"] = sid
|
112
|
-
|
95
|
+
session_data["session_id"] = sid
|
96
|
+
session_data
|
113
97
|
end
|
114
98
|
|
115
99
|
def set_cookie(request, session_id, cookie)
|
@@ -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.
|