The Ruby Debugger

The console is fun for tinkering and can be extremely useful for trying things out, but it’s a completely separate process from the way you (and your users) normally run Rails applications.

Note

Unfortunately, Heroku does not appear to support the Ruby debugger at the time of writing. Hopefully it will appear eventually.

If you do a search on Rails debugging, you’ll find lots of information on the Rails breakpointer. Unfortunately, the breakpointer depended on a bug in Ruby itself, one that was fixed in Ruby 1.8.5, so the breakpointer is now defunct. Instead, the most common current approach uses the Ruby debugger. It’s installed as a gem called ruby-debug. From the command line, you can install it with:

$ sudo gem install ruby-debug
Password:
Building native extensions.  This could take a while...
Building native extensions.  This could take a while...
Successfully installed linecache-0.43
Successfully installed ruby-debug-base-0.10.1
Successfully installed ruby-debug-0.10.1
3 gems installed
Installing ri documentation for linecache-0.43...
Installing ri documentation for ruby-debug-base-0.10.1...
Installing ri documentation for ruby-debug-0.10.1...
Installing RDoc documentation for linecache-0.43...
Installing RDoc documentation for ruby-debug-base-0.10.1...
Installing RDoc documentation for ruby-debug-0.10.1...

If you’re on Windows or certain Linux installs, the sudo part may be unnecessary.

Note

If you get a “Can’t find header files for ruby” error message, your Ruby install has left off some of the developer-only components. Header files are not installed automatically with Mac OS X, for example. You’ll need to install Xcode tools from the Optional Installs/Xcode Tools.mpkg directory on the Leopard DVD. (This is a large and long install!) On other platforms, you may need to install a ruby-devel package.

Once the gem is installed, you can use Ruby debugger with any Rails application on your computer, but you have to tell the Rails app to make the debugger available. To do this, open the config/environments/development.rb file and add the line:

require "ruby-debug"

This will make the debugger available in development mode (where you are now). You should probably only add it so that it applies in development mode, and leave test.rb and production.rb alone.

The next step is to add the debugger call in one of the controller methods. For a test, modify the create method in app/controllers/students_controller.rb (as is done in ch11/students005) so that it looks like:

def create
    @student = Student.new(params[:student])
    debugger
    respond_to do |format|
      if @student.save
        flash[:notice] = 'Student was successfully created.'
        format.html { redirect_to(@student) }
        format.xml  { render :xml => @student, :status => :created, :location =>
@student }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @student.errors, :status =>
:unprocessable_entity }
      end
    end
  end

Now, when you start the application with script/server, visit http://localhost:3000/students/new, and enter a new student, you’ll see something like Figure 11-1.

The most important part of Figure 11-1 is the status bar at the lower left: Waiting for localhost…. That’s unusual, unless you’ve accidentally put an infinite loop into your application. If you check the logs in the window where you ran script/server, you’ll see that it’s waiting for your input at an (rdb:1) prompt:

Processing StudentsController#new (for 127.0.0.1 at 2008-07-18 17:36:08) [GET]
  Session ID: BAh7BzoMY3NyZl9pZCIlODAyYjI1YTBiM2VhZGRiNzQxOGFiNjdmMmUzMDIx
NjUiCmZsYXNoSUM6J0FjdGlvbkNvbnRyb2xsZXI6OkZsYXNoOjpGbGFzaEhh
c2h7AAY6CkB1c2VkewA=--bc9174a5ce9b68d09c31910b2052c35034350eee
  Parameters: {"action"=>"new", "controller"=>"students"}
Rendering template within layouts/students
Rendering students/new
Rendered _navigation (0.00010)
Completed in 0.14174 (7 reqs/sec) | Rendering: 0.13218 (93%) | DB: 0.00000 (0%) |
200 OK [http://localhost/students/new]
/Users/simonstl/Documents/RailsOutIn/current/code/ch11/students001d/app/controllers
/students_controller.rb:45
respond_to do |format|
(rdb:1)
Waiting for a response because the debugger kicked in

Figure 11-1. Waiting for a response because the debugger kicked in

The line above the prompt is the next statement to be executed, if you type next. Unsurprisingly, it’s the line right after debugger. If you type list, you can see where you are, marked by =>:

(rdb:1) list
 [40, 49] in
/Users/simonstl/Documents/RailsOutIn/current/code/ch11/students001d/app/controllers
/students_controller.rb
   40  # POST /students
   41  # POST /students.xml
   42    def create
   43      @student = Student.find(params[:id])
   44  
=> 45      respond_to do |format|
   46      if @student.save
   47          flash[:notice] = 'Student was successfully created.'
   48          format.html { redirect_to(@student) }
   49          format.xml  { render :xml => @student, :status => :created,
:location => @student }

To see a list of the available commands, type help. The main ones you’ll need at first to move through code are:

  • next (or step) to move forward to the next line

  • cont to leave the debugger and let the program continue

  • quit to leave the debugger and shut down Rails

Following code for any extended period will likely drop you into the Rails framework code, which may be confusing at first. You’ll want to enter your debugger commands and other breakpoints close to where you think problems exist, or patiently wait for Rails to get out of your way.

While you’re in the debugger, you will probably want to inspect variables, which you can do with the p (or pp) command:

(rdb:1) p @student
#<Student id: 6, given_name: "Geramiah", middle_name: "Tinke", family_name:
"Weruzian", date_of_birth: "1989-02-18", grade_point_average:
#<BigDecimal:20de0d8,'0.377E1',8(8)>, start_date: "2007-09-16", created_at: "2008-
07-18 21:39:05", updated_at: "2008-07-18 21:39:05">

If you want prettier view of the data or if you’re just more comfortable in irb, you can jump into irb and tinker as you like. When you’re done working in irb, type exit or quit and you’ll be returned to the debugger shell. (When you enter irb, the prompt changes to >>, and when you exit, it returns to (rdb:#), where # is a number.) For example, the following session goes into irb to print the @student object as YAML, using the y command explored earlier:

(rdb:1) irb
>> y @student
--- !ruby/object:Student 
attributes: 
  start_date: "2007-09-16"
  updated_at: 2008-07-18 21:39:05
  id: "6"
  family_name: Weruzian
  given_name: Geramiah
  date_of_birth: "1989-02-18"
  created_at: 2008-07-18 21:39:05
  grade_point_average: "3.77"
  middle_name: Tinke
attributes_cache: {}

=> nil
>>  exit
/Users/simonstl/Documents/RailsOutIn/current/code/ch11/students001d/app/controllers
/students_controller.rb:62
respond_to do |format|
(rdb:1)

In development mode, Rails will reload your files for every request before you get into the debugger, but if you want the debugger to reload your files for every step, you can issue the command set autoreload. It will go much more slowly, but sometimes that’s OK for delicate surgery.

For much more detail on using the Ruby debugger with Rails, including features like setting breakpoints from within the debugger and TextMate integration, check out Patrick Lenz’s excellent tutorial at http://www.sitepoint.com/article/debug-rails-app-ruby-debug.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset