Debugging by raising exceptions is far easier than squinting through
byebug. Those tools should not be your first step.
The fastest way to debug Ruby (especially Rails) code is to
raise an exception along the execution path of your code while calling
.inspect on the method or object (e.g.
In the above code,
raise triggers an
Exception that halts execution of your code, and returns an error message that conveniently contains
.inspect information about the object/method (i.e.
foo) on the line that you're trying to debug.
This technique is useful for quickly examining an object or method (e.g. is it
nil?) and for immediately confirming whether a line of code is even getting executed at all within a given context.
Only after you have information about the state of your codes execution flow should you consider moving to a ruby gem irb debugger like
byebug where you can delve more deeply into the state of objects within your execution path.
To use the
byebug gem for debugging in Rails:
gem 'byebug'inside the development group in your Gemfile
byebuginside the execution path of the code you want examined.
byebug variable when executed will open up an ruby IRB session of your code, giving you direct access to the state of objects as they are at that point in the code's execution.
IRB debuggers like Byebug are useful for deeply analyzing the state of your code as it executes. However, they are more time consuming procedure compared to raising errors, so in most situations they should not be your first step.
When you are trying to debug a problem, good advice is to always: Read The !@#$ing Error Message (RTFM)
That means reading error messages carefully and completely before acting so that you understand what it's trying to tell you. When you debug, ask the following mental questions, in this order, when reading an error message:
In the stack trace pay particular attention to lines of code that come from your project (e.g. lines starting with
app/... if you are using Rails). 99% of the time the problem is with your own code.
To illustrate why interpreting in this order is important...
You execute code that at some point executes as such:
@foo = Foo.new ... @foo.bar
and you get an error that states:
undefined method "bar" for Nil:nilClass
Beginners see this error and think the problem is that the method
bar is undefined. It's not. In this error the real part that matters is:
for Nil:nilClass means that
@foo is Nil!
@foo is not a
Foo instance variable! You have an object that is
Nil. When you see this error, it's simply ruby trying to tell you that the method
bar doesn't exist for objects of the class
Nil. (well duh! since we are trying to use a method for an object of the class
Unfortunately, due to how this error is written (
undefined method "bar" for Nil:nilClass) its easy to get tricked into thinking this error has to do with
undefined. When not read carefully this error causes beginners to mistakenly go digging into the details of the
bar method on
Foo, entirely missing the part of the error that hints that the object is of the wrong class (in this case: nil). It's a mistake that's easily avoided by reading error messages in their entirety.
Always carefully read the entire error message before beginning any debugging. That means: Always check the class type of an object in an error message first, then its methods, before you begin sleuthing into any stacktrace or line of code where you think the error may be occurring. Those 5 seconds can save you 5 hours of frustration.
tl;dr: Don't squint at print logs: raise exceptions instead. Avoid rabbit holes by reading errors carefully before debugging.