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.
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.
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)
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:
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.