When your code does not behave as expected, you can use a debugger statement ("breakpoint") at any point in your code. This statement will open a REPL Show archive.org snapshot ("console") that you can use to inspect the current state of the program and move the control flow ahead manually.
Use debugging tools to find the exact line in the code where your expectation does not match the actual behavior. Since we use open source for everything, we can always find that line. When you ask a colleague for help, they will be able to help you better when you have already located the issue.
Learning to help yourself and ask good questions
- Hilfe, ich hänge beim Programmieren fest! 🇩🇪
- The XY Problem Show archive.org snapshot
- Getting Unstuck Show archive.org snapshot
- Rubber ducking: not just a funny phrase
Debugging in Ruby
Note
Running your server as part of a single combined terminal with the
bin/dev
command makes Ruby debugging harder.
To work around this, you should start your web server in a separate terminal as described above. If you are using terminator, bin/term is the easiest way to to achieve this.
- Include the
byebug
gem in yourGemfile
. This provides debugging for your app. - At any line, insert the command
byebug
ordebugger
. - When you start your app and the Ruby interpreter passes this line, this will open a debugging console. Do this.
- Note that when your app is a web app, the console running your
rails server
will pause the server and show the debugging console. Your browser will "hang" while that debugging console is open. - Note that the byebug console is not a full
irb
console, even though it somewhat behaves that way.
- Note that when your app is a web app, the console running your
- Use the
byebug README
Show archive.org snapshot
, byebug's
help
command (checkhelp help
for its usage) and our byebug cheatsheet to learn to do the following in the debugging console:- Understand your current position in the program
- Read local variables
- Call methods that are reachable from the current scope
- Switch into a full
irb
console and back to byebug - Move the program position one statement ahead
- Jump into the next method call
- Jump out of the current method call
- Exit debugging console and resume program
- Use a simple
raise
statement e.g. in controller code and open the corresponding page with your browser- better_errors Show archive.org snapshot provides you with a nice REPL for this specific use case
- If you need to debug code that is part of a gem like
rails
, just (temporarily) add aputs
ordebugger
statement to its source files. Ruby is an interpreted language after all!- Using Ruby's class Method for inspecting and debugging methods can be quite handy here too, since the interpretation might even change the source code or the defined location of the method.
- You should be in a habit of reviewing your code before committing. Never commit a debugging breakpoint.
- You can achieve this by using
git add -p
and following the guidelines Show archive.org snapshot from the referred card above.
- You can achieve this by using
- If you are debugging
rspec
tests, you can userspec -b
to print the full stack trace. - If you encounter problems caused by ActiveRecord and its database mapping, you can run ActiveRecord's query methods in the rails console and it will log the exact database interaction with related sql commands and its result.
- Before you know where to debug, you will often find yourself staring at logs beforehand - they are your friend at this mission!
- Use
Rails.logger.info()
to add your own custom messages tolog/<environment>.log
- Use
tail -f log/development.log
for a live view of the local Rails server's log - ..or
tail -f log/test.log
to see the same for RSpec tests!
- Use
Different debugging libraries
Ruby has always had multiple gems for debugging. When you're working on a customer project you need to check the Gemfile
to see which one is used.
All Ruby debugging gems have the same basic functionality:
- Add a breakpoint
- Get an IRB-like console when the breakpoint is reached
A debugging gem will also offer commands to step through your program, but their names differ from gem to gem.
Each gem also uses a different expression to set a breakpoint:
Gem | Breakpoint |
---|---|
pry Show archive.org snapshot | binding.pry |
byebug Show archive.org snapshot | byebug |
debug Show archive.org snapshot | binding.break |
Debugging in JavaScript
- At any line, insert the command
debugger
- When a modern browser's JavaScript interpreter passes this line, this will open a debugging console if developer tools are already open. Do this.
- Note that since JavaScript is single-threaded, you cannot interact with your app's frontend while the debugging console is open.
- Use the
Google DevTools debugging guide
Show archive.org snapshot
to learn to do the following in the browser's debugging console:
- Understand your current position in the program
- Read local variables or
this
. Observe how Chrome will automatically show the state of local variables in the Sources tab. - Call functions that are reachable from the current scope
- Move the program position one statement ahead
- Jump into the next method call
- Jump out of the current method call
- Exit debugging console and resume program
- Skim over DevTools card to get a rough overview about its many capabilities
- You should be in a habit of reviewing your code before committing (e.g. by using
git add -p
). Never commit a debugging breakpoint.
Debugging in Cucumber scenarios
- If you haven't done so already, configure Capybara to open Chrome for scenarios tagged with
@javascript
. - When you use
Spreewald
Show archive.org snapshot
you can open a debugging console at any line in your Cucumber scenario, by saying
Then console
. Do this. - Try this out from a debugging console:
- Use
page.find(...)
to inspect the current DOM. - In a
@javascript
scenario, observe the current frontend state in the Selenium-controlled browser. If you run E2E tests in headless Chrome, you may need to re-run the test with a visible Chrome window (NO_HEADLESS=1
). Note how you can even use the developer tools in the Selenium-controlled browser to inspect the DOM or run commands on the JavaScript console.
- Use
- When a step fails and you don't know why, it is often a good idea to open a debugging console right before the failing step.
- You can put debug statements within Ruby code as well.
- To check the server log, enter
tail -f log/test.log
in your terminal to print the server log while the test is running. - To print the full stack trace you can use
cucumber -d ...
Debugging network traffic
- Your browser DevTools have a Network tab. You can use it to observe outgoing network requests and their responses.
- Try this with an app like cards:
- Open developer tools and go to the Network tab
- Check Preserve log in the tab's settings so the list isn't cleared before a full page load.
- Switch between a few cards. What requests and responses do you see?
- Update an existing card. Find your form data ("params") in the the relevant request entry in the Network tab.
- Find out how to throttle the network traffic in your browser to simulate a slow internet connection
- You can also use the
curl
command in your terminal to print the response of a request.
Debugging DOM changes
- In your browser you can right-click any element and choose Inspect.
- This will open a tree displaying the current state of the DOM. The tree is live, so it will be updated automatically when your DOM changes.
- Do this on the large hero photo at
https://makandra.com/
Show archive.org snapshot
.
- Can you find the element for the photo?
- Observe how the DOM changes as the photos are rotated every few seconds.