Ruby on Rails
HowtoSendEmailWhenRailsThrowsAnException

UPDATE: This is now available as an ExceptionNotification plugin.

TobiasLuetke shared this tip on his blog.

Just add this code to your application.rb


  protected  
 
  def log_error(exception) 
    super(exception)
 
    begin
      ErrorMailer.deliver_snapshot(
        exception, 
        clean_backtrace(exception), 
        @session.instance_variable_get("@data"), 
        @params, 
        @request.env)
    rescue => e
      logger.error(e)
    end
  end

If you want this to stick in development mode as well you need to add


  def local_request?
    false
  end

Sample Mailer (generate using script/generate mailer ErrorMailer then edit app/models/error_mailer.rb)


class ErrorMailer < ActionMailer::Base
 
  def snapshot(exception, trace, session, params, env, sent_on = Time.now)

    # [nazgum]: Setting the content-type like this did not work for me
    #@headers["Content-Type"] = "text/html"

    # Setting the content-type like this does:
    content_type "text/html"
 
    @recipients         = 'target @ domain.tld'
    @from               = 'Error Mailer <error @ domain.tld>'
    @subject            = "[Error] exception in #{env['REQUEST_URI']}"
    @sent_on            = sent_on
    @body["exception"]  = exception
    @body["trace"]      = trace
    @body["session"]    = session
    @body["params"]     = params
    @body["env"]        = env
  end
 
end

app/views/error_mailer/snapshot.rhtml:


<style>
<!--
 
* {	font-size:	9pt;	font-family:	verdana, helvetica, arial, sans-serif; line-height: 1.7em; }
p { margin: 0 }
-->
</style>
<h2>Error report from <%= Time.now %></h2>
 
<table border="0">
<tr><td>Message</td><td><%= @exception.message %></td></tr>
<tr><td>Location</td><td><%= @env['REQUEST_URI'] %></td></tr>
<tr><td>Action</td><td><%= @params.delete('action') %></td></tr>
<tr><td>Controller</td><td><%= @params.delete('controller') %></td></tr>
<tr><td>Query</td><td><%= @env['QUERY_STRING'] %></td></tr>
<tr><td>Method</td><td><%= @env['REQUEST_METHOD'] %></td></tr>
<tr><td>SSL</td><td><%= @env['SERVER_PORT'].to_i == 443 ? "true" : "false"  %></td></tr>
<tr><td>Agent</td><td><%= @env['HTTP_USER_AGENT']  %></td></tr>
<% if @session['user'] -%>
<tr><td>User id</td><td><%= @session['user'].id %></td></tr>
<tr><td>User name</td><td><%= @session['user'].name %></td></tr>
<tr><td>User email</td><td><%= @session['user'].email %></td></tr>
<tr><td>Registered</td><td><%= @session['user'].created_at %></td></tr>
<% end -%>
</table>
 
<h3>Backtrace</h3>
<div><%= @trace.to_a.join("</p>\n<p>") -%></div>
 
<h3>Params</h3>
<hr/>
<% for key, val in @params -%>
<p><b><%= key %></b></p>
<p><%= val.to_yaml.to_a.join("</p>\n<p>    ") %></p>
<% end if @params -%>
 
<h3>Session</h3>
<hr/>
<% for key, val in @session -%>
<p><b><%= key %></b></p>
<p><%= val.to_yaml.to_a.join("</p>\n<p>    ") %></p>
<% end if @session -%>
 
<h3>Environment</h3>
<hr/>
<table border="0">
<% for key, val in @env -%>
<tr>
  <td>
    <small><b><%= key %></b></small>
      
  </td>
  <td>
    <small><%= val %></small>
  </td>
</tr>
<% end if @env -%>
</table>