Debugging strategies using binding.pry in Rails
May 18, 2022
Something I had to get used to when switching to primarily Ruby on Rails development while working at Unabridged is debugging using binding.pry
instead of a step-debugger tool.
pry
lets you stop the execution of running code, and inspect the values of all the in-scope variables at that point or run arbitrary code in that environment to figure out what's going wrong.
I was dealing with some tricky bugs the other day and asked my coworkers for strategies they use to more effectively work with pry
. Here are some of what we all came up with:
# Set the binding conditionally
This is helpful when you're processing a bunch of things and only one of them is causing trouble.
a_bunch_of_records.each do |record|
do_some_stuff
binding.pry if record.id == 1234
more_stuff
end
# use up
and down
These move the stack frame up
or down
respectively. Melinda told me about these methods which were exactly what I needed to solve my problem - the error was thrown in a method call based on what was getting passed in, but I needed to jump up the call stack to look at why that problematic data was getting passed in rather than what I should have had.
You can also keep going with next
, which goes to the next line, and continue
, which resumes normal execution until a pry is hit again.
# tap
a method
Drew's favorite method is using tap
on the result of a method.
do_some_stuff.tap do |result|
binding.pry if result.is_bad?
end
tap
passes the result of your method to a block, like so:
def tap
yield(self)
self
end
so instead of taking some_operation_to_debug
and converting it to:
res = some_operation_to_debug
binding.pry
res
you can use tap
!
# Ways to stop bindings from being hit
# Set the binding unless you $skip_binding
Another variation on conditional binding, Nick likes to use
binding.pry unless $skip_binding
So that when he's done, he can do $skip_binding = true
and let execution continue instead of stopping the whole server in order to make the binding stop getting hit. (The $
prefix on the variable makes it a global variable in Ruby).
# disable-pry
Dre pointed out that Pry also has a built-in disable-pry
command which just continues without hitting any more prys.