Topher Fangio
Topher Fangio

Reputation: 20667

Rendering and re-raising exceptions in Rails controllers

I'm creating an API in Rails and I've run into a situation where I'd like to alert the user that something bad happened by passing them some JSON with an error message. However, I'd also like to re-raise the exception so that Airbrake (formerly Hoptoad) will still catch the error and notify us so that we can look into the problem a bit more.

I'm currently catching the error like so:

begin
  if @myobject.update_attributes(:foo => "bar")
    render :json => @myobject, :status => :ok
  else
    render :json => @myobject.errors, :status => :unprocessable_entity
  end
rescue Exception => e
  render :json => { :errors => { :message => "Uh oh! Something went wrong." } }
  raise e
end

The problem is that my client never gets the JSON message since the raise e stops it from rendering and sends it a generic 500 error.

How should I fix this?

[My Solution]

As suggested by Jordan below, I simply call notify_airbrake(ex) in my code any time that I catch the exception. However, I abstracted it slightly by adding the following to my ApplicationController so that I can easily change from Airbrake to something else in the future:

class ApplicationController < ActionController::Base
  ...

  def notify_exception_service(ex)
    notify_airbrake(ex)
  end

  ...
end

So, instead of notify_airbrake(ex) I just call notify_exception_service(ex).

Upvotes: 3

Views: 2159

Answers (2)

Jordan Running
Jordan Running

Reputation: 106027

From the Airbrake gem documentation:

If you want to log arbitrary things which you've rescued yourself from a controller, you can do something like this:

rescue => ex
  notify_airbrake(ex)

  flash[:failure] = 'Encryptions could not be rerouted, try again.'
end

The #notify_airbrake call will send the notice over to Airbrake for later analysis. While in your controllers you use the notify_airbrake method, anywhere else in your code, use Airbrake.notify.

You don't have to re-raise the exception in order to log it with in Airbrake.

Upvotes: 3

Francesco Belladonna
Francesco Belladonna

Reputation: 11689

As I've said on chat, I think you can't becouse of how rails render things. When you call render, a @_something_render_variable is set, but the page is not directly render, there is still additional call. Raising an exception obviusly block this flow, actually breaking the render of the webpage.

Changing this behaviour is really hard, you must alias the render method and work on it, I had a similar problem.

Upvotes: 2

Related Questions