Tests, logging (e.g.
debug), traditional output (e.g.
puts), and raising exceptions will assist you with finding most issues. However, there are situations when you are unsure about the state of several variables within a context or the state of a complex object within a given interaction. This is when it is useful to employ an interactive debugger.
ruby-debug is a powerful tool that allows for you to stop the execution of the application at a particular moment and to investigate and interact within that context.
- Output the state and value of objects, variables all available within that scope.
- Move step-by-step through the code to ensure that your mental model of the execution maps to the actual execution.
- Change the state of objects to quickly test the effects within the system
The debugger is an external gem. You can install in manually:
Note: if you’re using 1.8.7 install the gem named
ruby-debug. Then, as soon as possible, stop using Ruby 1.8.7 :)
In Plain Ruby
Using the debugger in a normal Ruby application is straightforward:
1 2 3 4 5 6 7
You require the library, then call the
debugger method which is defined by the library. When you run the code and it hits the
debugger call, you’ll drop into an interactive prompt with many commands available. Skip down to Basic Usage.
When you start your Rails server or console you have to explicitly enable the debugger. For the server:
And for the console:
Now the debugger is loaded, and any call to the method
debugger in your code will trigger it.
Interrupting Request/Response Execution
Wherever you want to inspect execution add a call to
debugger like this:
1 2 3 4 5
If the debugger is not loaded when execution hits the
debugger line, there will be a warning in the output log.
If it is properly loaded, execution will pause and drop you into the debugger interface. If you’re in the middle of a request this console will appear in the window/process where your server is normally outputting its logging information:
1 2 3 4
Which can be read like this:
- Line 1: Normal server startup line
- Line 2: The line of code containing the call to
- Line 3: The next line of code pending execution
- Line 4: The debugger prompt
Now you have incredible power available to you with a few simple commands.
Say you figure out the issue and you’re ready to finish the request. Enter
continue and execution will keep running from wherever it paused.
Rarely you want to exit the application all together. Quit will halt execution without finishing the request.
list instructions shows the context of the current code, five lines before and four lines after the current execution point.
next instruction will run the following instruction in the current context and move the marker to the next line in that context. Given this controller code:
1 2 3 4 5 6
next moves the execution marker:
1 2 3 4 5 6
It advances from the
if @article.save to the
step command, on the other hand, will move the execution marker to the next instruction to be executed even in a called method. Using the same controller code as before, see how
step has a different effect:
1 2 3 4 5 6
Execution has now paused inside the implementation of
eval Ruby Code
You can use the
eval instruction to run arbitrary ruby or display the value of a variable. For instance, to see the value of
1 2 3 4 5
Watching Variables with
Typically when running the debugger you’re interested in how a variable changes over a series of instructions. First, let’s move the debugger call up one line in our action:
1 2 3 4 5
I run that code then use the
display command like this:
1 2 3 4 5 6 7 8 9 10 11 12 13
- In line 3 I tell the debugger to
- It will then show a line like #4 for each prompt.
nilwhich shows up blank like running
- Then after I call
nextand a value is assigned to
@article, the value appears on line 6.
- Notice that the display persists for later instructions like line 10.
In fact, when you
display a variable it will show up for all further debugger calls in that process. So if your server stays running, you’ll see variables displayed from a previous request’s debugging.
Want to stop displaying a variable? Call
undisplay with the number displayed next to the variable. So in this case, I’d see the
1: next to
@article and call
Dropping into IRB
Not satisfied with those options? Call the
irb method and the debugger will drop you into a normal IRB console. Use all your normal Ruby functions and tricks, then
exit to get back to the debugger. You can continue to invoke other instructions and any data you created/changed in the IRB session is persisted in the debugging session.
Almost all of the commands (e.g.
step) can be executed by using the first letter of the command. Allowing you to
continue by entering the letter
All the commands that you have executed are in a command buffer that you can interact with by using the arrow keys. The
up-arrow will move you back in history by one command. The
down-arrow will move you forward in history.
The last command that you executed will be executed again by pressing the
return key. This is extremely useful if you want to continually
step through the code and want to save yourself the requirement of typing
s or accessing the previous commands in the history.
Use the Blogger sample application to complete the exercises in this section. See the Setup Instructions for help.
- Start the server without
--debug, then call
debuggerin the code, and observe the output
- Start the server with
--debugand add a breakpoint to a controller method. Trigger that breakpoint and experiment with each of these commands:
debuggeris just a method. Try combining it with a conditional branch to only execute on a certain pathway through your code (like a
nilinput, for example).
- Rails guide on debugging and the debugger: http://guides.rubyonrails.org/debugging_rails_applications.html