Debugging Rails application

Posted on September 14, 2006

In this article I am going to describe several ways you can debug your Rails application with ruby-debug starting from simplest and proceeding with more sophisticated setup.

Simplest of all

The simplest and most obvious way is to start your application with rdebug script:

    $ rdebug ./script/server webrick

This method doesn't work with lighttpd since the latter starts several child Rails processes.

When you execute this command you end up with debugger prompt where you can set up your breakpoints.

Debugging without rdebug script

First you need to activate the debugger in your development.rb file:

    ./config/environments/development.rb:

    ...
    require 'ruby-debug'
    Debugger.start

Now you can use Kernel#debugger method to activate debugger:

    def my_action
      debugger
      ...
    end

Remote debugging.

If for some reason you want to connect remotely to debugger, you can start it with remote debugging enabled:

    $ rdebug -s ./script/server webrick

and then connect to it with

    $ rdebug -c
    Connected.
    /usr/local/lib/ruby/1.8/webrick/server.rb:91: if svrs = IO.select(@listeners, nil, nil, 2.0)
    (rdb:1)

Once again, at this point you can add breakpoints and proceed.

Adding breakpoints directly in your code

What if you don't want to setup breakpoints all the time from the debugger's command prompt and you want to use Kernel#debugger method instead. In this case when you start a debugger, you should notify it not stop when a remote client is connected with -n option:

    $ rdebug -sn ./script/server webrick

Remote debugging without rdebug script

As always activate your debugger in development.rb file:

    ./config/environments/development.rb:

    ...
    require 'ruby-debug'
    Debugger.start_remote

Here you can control it with two options:

    ./config/environments/development.rb:

    ...
    require 'ruby-debug'
    Debugger.wait_connection = true
    Debugger.stop_on_connect = true
    Debugger.start_remote
  • Debugger.wait_connection options makes debugger wait until you connect to it remotely.

  • Debugger.stop_on_connect drop you to the debugger prompt as soon as you connect to it.

The method I use most of the time

All described so far methods suffer from one thing: the debugger is always activated. It can slow down your application significantly. What if I want to activate it only in a particular place in my code? As always there are two ways to do that. But first you should only require debugger in development.rb file without starting it:

    ./config/environments/development.rb:

    ...
    require 'ruby-debug'
  • Debugger#start takes a block:

    def my_action
      ...
      # at this point the debugger is still disabled
      Debugger.start do
        # here debugger is enabled
        # below goes the code you want to debug
        ...
      end
      # at this point the debugger is disabled
      ...
    end
    
  • Use Module#debug_method (available since version 0.4.2):

    class MyController < ApplicationController
      def my_action
        ...
      end
      debug_method :my_action
    end
    

    Now whenever you reach my_action method, the debugger is activated.

Comments
  1. Sergio BMarch 10, 2007 @ 05:02 PM

    Hi,

    I want to use ruby-debug just like the Rails breakpointer works but I must be missing something.

    I tried multiple combinations of the methods described above without any luck. Is there like a step-by-step article on how to use it?

  2. Sergio BMarch 10, 2007 @ 06:38 PM

    ok I guess it wasn't that hard after all :)

    For reference, here's how I got it working:

    1) Add this 2 lines to development:

    require 'ruby-debug' Debugger.start

    2) stop and start with ./script/server webrick

    3) put "debugger" on the line where you want the code execution to stop.

    4) Run the code from the browser and go back to terminal. You should see something like (rdb:2) on the last line

    5) type "irb". You should now have everything at your fingertips! (You could also type "help" to see all available commands).

    Awesome stuff Kent! Thanks so much.

  3. NetManiacMarch 15, 2007 @ 07:57 AM

    Well... I'm stuck with it in point 4: since after putting 'debugger' and pointing browser to this method I got

    RuntimeError in ReportController#horiz

    Breakpoints are not currently working with Ruby 1.8.5

    And of course script/server does not return to any kind of prompt.

    Should it be default Rails 'breakpoint' service disabled?

  4. Kent SibilevMarch 15, 2007 @ 11:29 AM

    @NetManiac,

    Is it possible that RuntimeError happens before debugger method is executed?

    Breakpoint library is not working with ruby 1.8.5, but you don't need to explicitly disable it.

  5. NetManiacMarch 19, 2007 @ 07:29 AM

    @Kent Don't think so.

    Rails is complaining about 'buggy debugger' statement, so program flow reaches this place. without debugger statement there is RuntimeError, but few lines later.

    I will try to generate some example code.

  6. NetManiacMarch 19, 2007 @ 07:50 AM

    Well.. simple app generated on this machine works with debugger flawless. )

  7. IanMay 04, 2007 @ 06:50 PM

    I've been playing with ruby-debug in the hopes of getting it to work with my Rails application under Apache with either CGI or FastCGI.

    I started with the "Remote Debugging Without rdebug Script" section but quickly ran into problems. For starters, I had to manually define ENV["HOME"], as required by ruby-debug/interface.rb:24. Doing this allowed Rails to continue operation without interruption. Unfortunately, rdebug -c doesn't seem to catch anything when the Rails application is run with a call to debugger somewhere in the source.

    I wouldn't mind looking into writing a patch if I could get a hint as to what might be the cause. Or is this a futile cause?

    Beyond this, I tried those other settings for Debugger that you wrote about. Setting waitconnection to true caused a ThreadError during the wait call. Setting stopon_connect to true caused a NoMethodError. Has that option been replaced or just dropped entirely?

  8. Andrew CarterJanuary 07, 2008 @ 04:51 PM

    I was using the following line on pre-0.10 ruby-debug with success. Now it is failing:

    rdebug -sn ./script/server mongrel

    I now get:

    Library/Ruby/Gems/1.8/gems/ruby-debug-0.10.0/bin/rdebug:165:in debug_load': no such file to load -- mongrel (LoadError) from /Library/Ruby/Gems/1.8/gems/ruby-debug-0.10.0/bin/rdebug:165 from /usr/bin/rdebug:19:inload' from /usr/bin/rdebug:19

    I'm not sure what is causing this error. Has something changed in the latest ruby-debug that would break the previous command line I used?

Post a comment
Comment





You may use Markdown in your comments, so please give your code snippets a four-space indent.