Skip to content

Commit

Permalink
Merge pull request rails#8668 from guilleiguaran/exceptions
Browse files Browse the repository at this point in the history
New exceptions pages for development
  • Loading branch information
dhh committed Jan 1, 2013
2 parents 56aa02f + 25c8770 commit 8d945f4
Show file tree
Hide file tree
Showing 12 changed files with 258 additions and 65 deletions.
Expand Up @@ -42,7 +42,10 @@ def render_exception(env, exception)
:application_trace => wrapper.application_trace,
:framework_trace => wrapper.framework_trace,
:full_trace => wrapper.full_trace,
:routes => formatted_routes(exception)
:routes => formatted_routes(exception),
:source_extract => wrapper.source_extract,
:line_number => wrapper.line_number,
:file => wrapper.file
)

file = "rescues/#{wrapper.rescue_template}"
Expand Down
23 changes: 22 additions & 1 deletion actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
Expand Up @@ -25,7 +25,7 @@ class ExceptionWrapper
'ActionView::Template::Error' => 'template_error'
)

attr_reader :env, :exception
attr_reader :env, :exception, :line_number, :file

def initialize(env, exception)
@env = env
Expand Down Expand Up @@ -56,6 +56,15 @@ def self.status_code_for_exception(class_name)
Rack::Utils.status_code(@@rescue_responses[class_name])
end

def source_extract
if application_trace && trace = application_trace.first
file, line, _ = trace.split(":")
@file = file
@line_number = line.to_i
source_fragment(@file, @line_number)
end
end

private

def original_exception(exception)
Expand All @@ -81,5 +90,17 @@ def clean_backtrace(*args)
def backtrace_cleaner
@backtrace_cleaner ||= @env['action_dispatch.backtrace_cleaner']
end

def source_fragment(path, line)
return unless Rails.respond_to?(:root) && Rails.root
full_path = Rails.root.join(path)
if File.exists?(full_path)
File.open(full_path, "r") do |file|
start = [line - 3, 0].max
lines = file.lines.drop(start).take(6)
Hash[*(start+1..(lines.count+start)).zip(lines).flatten]
end
end
end
end
end
Expand Up @@ -20,12 +20,15 @@
<h2 style="margin-top: 30px">Request</h2>
<p><b>Parameters</b>: <pre><%=h request_dump %></pre></p>

<p><a href="#" onclick="document.getElementById('session_dump').style.display='block'; return false;">Show session dump</a></p>
<div id="session_dump" style="display:none"><pre><%= debug_hash @request.session %></pre></div>

<p><a href="#" onclick="document.getElementById('env_dump').style.display='block'; return false;">Show env dump</a></p>
<div id="env_dump" style="display:none"><pre><%= debug_hash @request.env.slice(*@request.class::ENV_METHODS) %></pre></div>

<div class="details">
<div class="summary"><a href="#" onclick="document.getElementById('session_dump').style.display='block'; return false;">Show session dump</a></div>
<div id="session_dump" style="display:none"><p><pre><%= debug_hash @request.session %></pre></p></div>
</div>

<div class="details">
<div class="summary"><a href="#" onclick="document.getElementById('env_dump').style.display='block'; return false;">Show env dump</a></div>
<div id="env_dump" style="display:none"><p><pre><%= debug_hash @request.env.slice(*@request.class::ENV_METHODS) %></pre></p></div>
</div>

<h2 style="margin-top: 30px">Response</h2>
<p><b>Headers</b>: <pre><%=h defined?(@response) ? @response.headers.inspect.gsub(',', ",\n") : 'None' %></pre></p>
@@ -0,0 +1,25 @@
<% if @source_extract %>
<div class="source">
<div class="info">
Extracted source (around line <strong>#<%= @line_number %></strong>):
</div>
<div class="data">
<table cellpadding="0" cellspacing="0" class="lines">
<tr>
<td>
<pre class="line_numbers">
<% @source_extract.keys.each do |line_number| %>
<span><%= line_number -%></span>
<% end %>
</pre>
</td>
<td width="100%">
<pre>
<% @source_extract.each do |line, source| -%><div class="line<%= " active" if line == @line_number -%>"><%= source -%></div><% end -%>
</pre>
</td>
</tr>
</table>
</div>
</div>
<% end %>
@@ -1,10 +1,16 @@
<h1>
<%=h @exception.class.to_s %>
<% if @request.parameters['controller'] %>
in <%=h @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%=h @request.parameters['action'] %><% end %>
<% end %>
</h1>
<pre><%=h @exception.message %></pre>
<header>
<h1>
<%=h @exception.class.to_s %>
<% if @request.parameters['controller'] %>
in <%=h @request.parameters['controller'].camelize %>Controller<% if @request.parameters['action'] %>#<%=h @request.parameters['action'] %><% end %>
<% end %>
</h1>
</header>

<%= render template: "rescues/_trace" %>
<%= render template: "rescues/_request_and_response" %>
<div id="container">
<h2><%=h @exception.message %></h2>

<%= render template: "rescues/_source" %>
<%= render template: "rescues/_trace" %>
<%= render template: "rescues/_request_and_response" %>
</div>
Expand Up @@ -4,7 +4,7 @@
<meta charset="utf-8" />
<title>Action Controller: Exception caught</title>
<style>
body { background-color: #fff; color: #333; }
body { background-color: #fff; color: #333; margin: 0px}

body, p, ol, ul, td {
font-family: helvetica, verdana, arial, sans-serif;
Expand All @@ -13,15 +13,103 @@
}

pre {
background-color: #eee;
padding: 10px;
font-size: 11px;
white-space: pre-wrap;
}

a { color: #000; }
pre.box {
border: #eee solid 1px;
padding: 10px;
margin: 0px;
width: 958px;
}

header {
background: whiteSmoke;
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr='#980905',endColorstr='#c52f24');
background: -webkit-gradient(linear,0% 0,0% 100%,from(#980905),to(#C52F24));
background: -moz-linear-gradient(270deg,#980905,#C52F24);
color: #fff;
padding: 0.5em;
}

h2 {
color: #C52F24;
padding: 2px;
line-height: 25px;
}

.details {
border: 1px solid #E5E5E5;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
margin: 1em 0px;
display: block;
width: 978px;
}

.summary {
padding: 8px 15px;
border-bottom: 1px solid #E5E5E5;
display: block;
}

.details pre {
margin: 5px;
border: none;
}

#container {
margin: auto;
width: 98%;
}

.source * {
margin: 0px;
padding: 0px;
}

.source {
border: 1px solid #D9D9D9;
background: #ECECEC;
width: 978px;
}

.source pre {
padding: 10px 0px;
border: none;
}

.source .data {
font-size: 80%;
overflow: auto;
background-color: #fff;
}

.info {
padding: 0.5em;
}

.source .data .line_numbers {
background-color: #ECECEC;
color: #AAA;
padding: 1em .5em;
border-right: 1px solid #DDD;
text-align: right;
}

.line:hover {
background-color: #f6f6f6;
}

.line.active {
background-color: #FFCCCC;
}

a { color: #980905; }
a:visited { color: #666; }
a:hover { color: #fff; background-color:#000; }
a:hover { color: #C52F24;}
</style>
</head>
<body>
Expand Down
@@ -1,2 +1,7 @@
<h1>Template is missing</h1>
<p><%=h @exception.message %></p>
<header>
<h1>Template is missing</h1>
</header>

<div id="container">
<h2><%=h @exception.message %></h2>
</div>
@@ -1,24 +1,27 @@
<h1>Routing Error</h1>
<p><pre><%=h @exception.message %></pre></p>
<% unless @exception.failures.empty? %>
<p>
<h2>Failure reasons:</h2>
<ol>
<% @exception.failures.each do |route, reason| %>
<li><code><%=h route.inspect.gsub('\\', '') %></code> failed because <%=h reason.downcase %></li>
<% end %>
</ol>
</p>
<% end %>
<%= render template: "rescues/_trace" %>
<header>
<h1>Routing Error</h1>
</header>
<div id="container">
<h2><%=h @exception.message %></h2>
<% unless @exception.failures.empty? %>
<p>
<h2>Failure reasons:</h2>
<ol>
<% @exception.failures.each do |route, reason| %>
<li><code><%=h route.inspect.gsub('\\', '') %></code> failed because <%=h reason.downcase %></li>
<% end %>
</ol>
</p>
<% end %>
<%= render template: "rescues/_trace" %>

<h2>
Routes
</h2>
<h2>
Routes
</h2>

<p>
Routes match in priority from top to bottom
</p>
<p>
Routes match in priority from top to bottom
</p>

<%= render layout: "routes/route_wrapper" do %>
<%= render partial: "routes/route", collection: @routes %>
Expand Down
@@ -1,17 +1,44 @@
<h1>
<%=h @exception.original_exception.class.to_s %> in
<%=h @request.parameters["controller"].capitalize if @request.parameters["controller"]%>#<%=h @request.parameters["action"] %>
</h1>
<% @source_extract = @exception.source_extract(0, :html) %>
<header>
<h1>
<%=h @exception.original_exception.class.to_s %> in
<%=h @request.parameters["controller"].capitalize if @request.parameters["controller"]%>#<%=h @request.parameters["action"] %>
</h1>
</header>

<p>
Showing <i><%=h @exception.file_name %></i> where line <b>#<%=h @exception.line_number %></b> raised:
<pre><code><%=h @exception.message %></code></pre>
</p>
<div id="container">
<p>
Showing <i><%=h @exception.file_name %></i> where line <b>#<%=h @exception.line_number %></b> raised:
<pre><code><%=h @exception.message %></code></pre>
</p>

<p>Extracted source (around line <b>#<%=h @exception.line_number %></b>):
<pre><code><%=h @exception.source_extract %></code></pre></p>
<div class="source">
<div class="info">
<p>Extracted source (around line <strong>#<%=h @exception.line_number %></strong>):
</div>
<div class="data">
<table cellpadding="0" cellspacing="0" class="lines">
<tr>
<td>
<pre class="line_numbers">
<% @source_extract.keys.each do |line_number| %>
<span><%= line_number -%></span>
<% end %>
</pre>
</td>
<td width="100%">
<pre>
<% @source_extract.each do |line, source| -%><div class="line<%= " active" if line == @exception.line_number -%>"><%= source -%></div><% end -%>
</pre>
</td>
</tr>
</table>
</div>
</div>

<p><%=h @exception.sub_template_message %></p>
<p><%=h @exception.sub_template_message %></p>

<%= render template: "rescues/_trace" %>
<%= render template: "rescues/_request_and_response" %>
<%= render template: "rescues/_trace" %>
<%= render template: "rescues/_request_and_response" %>
</div>
</div>
@@ -1,2 +1,6 @@
<h1>Unknown action</h1>
<p><%=h @exception.message %></p>
<header>
<h1>Unknown action</h1>
</header>
<div id="container">
<h2><%=h @exception.message %></h2>
</div>

0 comments on commit 8d945f4

Please sign in to comment.