Jaap Haagmans The all-round IT guy

8Aug/130

Capture errors and debug your Ruby on Rails app

When developing or maintaining a Ruby on Rails app, you'll frequently run into errors and exceptions. In development, this is just part of the process (trial and error is the best software development tool I know). In production, errors can be a big problem.

Development

Even so, in development you want to be able to quickly spot the error so you can move on. That's not always as easy as it sounds. Let's say you have a problem with a certain set of objects that don't behave like you expected them to.

<%= var.inspect %>

I've seen PHP programmers do this a lot. And when they start using Rails, they continue to do this. I'm not fond of this method. I've seen apps being deployed in production with these pieces of code still in them. You think it won't happen to you, but you won't always have time to fully review your code.

p var.inspect

This is not much better. You're not displaying anything on the page, but errors are still hard to track down.

gem 'debugger'

Now we're getting somewhere. The debugger gem enables you to stop code execution at some point, go to your console (where you'll now see a blinking cursor) and evaluate all variables available at that point in the code. This way you can easily dig deep into the variable, manipulate it and type "continue" when you're done to see the result in your browser.

group :development do
  gem 'better_errors'
  gem 'binding_of_caller'
end

Better Errors is a tool that extends Rails' error reporting framework. Where you'd normally see Rails' error page, you will now see a very nice page that will show you the portion of your code that triggered the error along with some relevant info and (thanks to the binding_of_caller gem) an interactive prompt that will, like debugger, enable you to do some digging.

Production

However, gems like better_errors should never be used in production. I hope I don't have to explain the risks of anyone being able to use an interpreter in your app from their browser. However, it would be nice if you'd still be able to get in depth knowledge of errors popping up in production. If not, you will have to wait for phone calls from clients. So, there are some nice tools available.

Airbrake

Airbrake (formerly known as Hoptoad) is a service that you can integrate into your Rails application using a gem. In the Airbrake dashboard, you will see every error that has occurred up to a year ago, including relevant information about the request and extensive traces. Airbrake comes with Github integration, meaning it can create Github issues from errors. Paid plans start at $7.- per month for two developers and there is a free plan available for us loners.

Errbit

Errbit is a self-hosted alternative to Airbrake. It's well maintained and it's free! And what I really love is that it has an integrated error reporting app for errors within Errbit itself! If they'd only have an app that can capture errors for the app that captures errors on the app that captures errors...

Honeybadger

Honeybadger is the second alternative to Airbrake. It's not really that different from Airbrake, but I really like the interface. Furthermore, I like their Javascript error tracking functionality which works wonderfully. Javascript debugging is very hard, especially since every browser behaves differently. Honeybadger helps you detect the browser and OS the user is running on and gives a trace on the Javascript error. It can also send you a text message when an error pops up in your app. Paid plans start and $19.- / month and they have a 15-day free trial available.

2Feb/110

How to update your bundle after every deploy

Rails 3 depends on Bundler for its gem management. It's a blessing for everyone on shared hosting plans, because gems don't need to be installed by the server administrator anymore. You can simply include them into your bundle, by adding them to your Gemfile. However, if you use Capistrano and you decide to add a new gem to your app, you will need to run the following command from your app root:

bundle install

The beauty of using Capistrano is that you can automate almost anything using your deploy script. Where in Rails 2, you might have used Capistrano to run a rake task to install gems, in Rails 3 you can do the same using Bundler. The following code did it for me:

1
2
3
4
5
6
7
8
9
10
after "deploy:update_code", "deploy:bundle_install"
 
namespace :deploy do
 
  desc "update your bundle"
  task :bundle_install, :roles => :app do
    run "cd #{release_path} && /opt/ruby/bin/bundle install --deployment --path ~/.bundler"
  end
 
end

The reason I specifically tell Bundler to keep the bundle in the home directory is that this way your bundle will properly work across all your releases. You might want to change the path to the bundle executable though.

Do note that, if you have included a new gem, your deploy will take significantly more time to finish from now. Though if the bundle hasn't changed, it will be updated in nearly no time at all.