Skip to main content
Presented by Collin for GoRails. Republished on AppSignal September 19, 2026. The debug gem is Ruby’s standard debugger, and Rails puts it in the development and test groups of every new application’s Gemfile. If you are still debugging with puts, it is already installed. The thing it does that print statements cannot is let you keep your place. You stop once, and then explore: read source, add more breakpoints, run to them, walk back up the stack, all without editing a file or restarting.

What this covers

  • Three ways into a debug session.
  • Moving through code with step, next, and continue.
  • Adding breakpoints mid-session, including in other files.
  • Walking the stack with backtrace, up, down, and frame.

Requirements

For a project without it:

Get into a session

Three entry points, all placed on the line you want to stop at. The prompt tells you where you are: irb for IRB, rdbg for the debugger. The third is worth knowing because binding.irb is a hard habit to break. If the debug gem is present, running any debugger command from an IRB session drops you into the debugger and runs it. You never have to go back and change the line.

Find your bearings

Two commands to run when you have lost track of where you stopped:
  • whereami prints the ten lines around the breakpoint.
  • list (or l) prints source, and takes a range: list 22-28.
help lists every command, grouped by what it does. help backtrace explains one of them. Entering through binding.irb also gives you IRB’s own show_source, which prints the source of a constant or method without you leaving the session:

Move through the code

Three commands, and the difference between the first two is the whole point. On a line that calls a method, step takes you inside that method. Keep stepping and you will eventually be inside Rails itself, reading Active Record’s source in the same session. next executes the whole line and stops on the following one. Use step when you suspect the call. Use next when you have ruled it out.

Add breakpoints without leaving

This is what makes the session worth staying in. break on its own lists the breakpoints you have set. Given an argument, it adds one.
The three forms are: a line in the current file, a path and line in any file, and a class and method with no line number at all. Reach for the last one. It is the only form you can use without going back to your editor to look up a line number. Then continue runs to it. The alternative is to stop, edit a file, restart, and step back to where you were. That costs you the state you had built up, and the train of thought with it.

Walk the stack

backtrace (or bt) lists the frames, each with an index.
  • up moves to the calling frame.
  • down moves back toward where you stopped.
  • frame 12 (or f 12) jumps straight to one.
up moves toward larger index numbers, which reads backwards against the printed list until you have done it once. In any frame, list shows that frame’s source and info shows its variables. info locals narrows that to local variables. Standing in a caller’s frame to read the arguments it passed down is often faster than stepping forward to see what a method received.

Debugging what you cannot reproduce

Everything above needs a breakpoint, which needs the problem to happen while you are watching. Production failures do not cooperate. That is the gap AppSignal fills, and the two workflows are complements rather than alternatives:
  • Error tracking captures the exception, its backtrace, and the request that caused it, whether or not anyone was watching.
  • Performance traces show the call as it happened, with timings, which is the closest thing to a backtrace for a request that has already finished.
  • Time Detective shows what the rest of the application was doing when the trace ran. A breakpoint cannot give you that after the fact.
  • Request parameters and custom data put the values on the incident. That is what info locals gives you locally, and it is usually the missing piece when reproducing something.
  • Exceptions your application rescues never reach Rails, so nothing reports them automatically. Report those yourself with exception handling.
The useful pattern is to let AppSignal tell you what failed and with which inputs, then use those inputs to reproduce it locally and set a breakpoint.

Transcript

Transcribed from the video and lightly edited: the automatic captions misheard a number of product and API names, and those have been corrected.
0:02 - Hello everybody, welcome back to another episode here at GoRails. In this week’s episode, we’re going to look at better debugging using the Ruby debug gem. So this is a gem that you’ll need to install or you can add it to your gem file if you’re working with a project with a gem file. And then one nice thing is that with a new Rails app, if you spin it up, as I’ve just done here, I’ve spun a new Rails app called Blah. If I open this up and we go look at the gem file, we will see, if we search for a debug here, we’ll see that the debug gem is added to your gem file by default in Rails to the development test groups, which is great.0:50 So this will allow us the ability to hop into a debug session using this gem and walk through our code and do some pretty nifty things to debug our applications. Okay, so I have our hackathon application over here and we’re gonna play around with the debug gem here and get a feel for some of the commands that we have access to and how to use them and how they can affect how we trace through our code here. So in order to get into a debug session, we have a few options in how to get there. So the first thing we can do, let’s go down into this current, or this latest method here in this event class. If I just pop into the first line, this method here, one thing we can do is we can type in binding.irb, perhaps you’re familiar with using binding.irb.1:43 And this, when we hit this break point, we will get into an IRB session, but then once we’re in that session, we can then execute the debug command or any of the other commands that are in the debug gem and that will then drop us into Ruby debug console session or prompt here. So let’s look at this first. So I’ll save this and hop over to another terminal tab here and I’m just gonna hop into the console in sandbox mode. Forgive me for using an alias here. If you see up in the, I know it’s probably small to read, but up here, you can see what RCS means over here.2:21 It just runs bin rails console dash S. So you get in sandbox there, it’s the little shell alias I have. So anyways, in here, I’m just gonna type event and then call that class method for latest here. If we hit enter here, we see that we hit that binding.irb break point, but the prompt here reflects that we’re in IRB, right? So what we can do here is to, in order to get into the Ruby debug prompt, we can just simply type debug, okay?2:52 If we do that, we see that our prompt changes now to RDBG. And now that indicates to us that we are in Ruby debug console here. So with this done now, what can we do here? So one thing we can do, I’m just gonna clear this console out while still staying in the Ruby debug console. I’m just gonna clear the terminal here so that we have some room to work.3:16 One thing we can do is use the command show_cmds here, hit enter, and then we can see a list of all the available commands that we have access to in this session here. So looking through some of these commands here, we have some IRB commands, we have some debugging commands, a few miscellaneous commands, some context commands, and so forth. So let’s start looking at some of the ones that I find the most handy to know how to use. So the first thing, now this is a command that’s also available in IRB, but it’s the whereami command. If you ever forget where you put the break point and what the code around it looks like, you can type this command and it’ll bring that up and show you the 10 lines around where that break point is.3:58 So we see right here, saying 13 through 22 in this file here. So it’s showing 10 lines plus or minus five of around where that break point is. So that’s how we can always bring back that context without having to scroll around or if we’ve cleared the terminal, we can get that context back of where we’re at in this session here. So whereami a great one to have? Also, another one that’s nice here is the list command.4:28 Now, a lot of the commands are available in the Ruby debug gem have shortcuts for. So for list, you can simply type L or you can type out the full word list. And one thing you can do is you can give it a range of line numbers. So for example, right now we can only see up to from 13 to 22, if I wanted to see what 22 to say 28 looked like, one thing I can do is type list or type L, I’ll just type list for now and then say 22 dash 28. Okay.5:05 Now we hit enter here. Now we see the lines that we’ve requested from this file, right on 22 through 28. So the list command is great. So one of the other ones that I really like is the show_source command. So we can say show_source and then give it, you know, a string of like constant that we want to look up.5:22 It can be a constant, we can send a method that we want to see, but I’ll just do this event constant for now show. So show_source event, we hit enter here. We can see all of the, oops, we can see all of the source code for that event class right here. Just simply by calling this. So we never have to leave this console session here and go back to our actual editor to recall this information.5:48 Additionally, we can look up just, you know, the source code for our method. So let’s look at that now. Let’s look up if we wanted to look up, you know, what the source code for the two-param method here looks like. And we didn’t already have this up. Let’s look at how to do that.6:03 So if we wanted to look up the two-param method, we could say show_source and then give it the string event. And then we can use the pound because it is in our hash symbol, excuse me. We can use this symbol or this to indicate that we want to look up the instance method two-param, right? So we’ll say hash two-param, close our string, hit enter. And now we see the source code for the two-param method.6:27 If we wanted to look up the current class method, then we could say show_source and then say event. And then we could do the double colons and then current, right here, close our string. Now we see the source code for the current class method, right? And we’re still in that Ruby debug session. We’ve never had to leave this console and go back to our source code.6:54 We can do it all from right here. So this is cool. One of my, one of the other commands I really like is just the info command. If we type info right here, we can see, you know, a big list of info. This is, you know, all of the variables and instance variables and stuff that we have right now within the context that we’re in available.7:11 So we can then, you know, grab this, for example. We can grab at generated associated methods, right? We can copy that. And like this points to an object here, where the methods available in that object. So we can say at generated associated methods.methods.sort, for example, and then before I run that, I’ll just clear the console, hit enter.7:34 And now we see all the methods available in that object there, right? So this is really cool. And again, if you forget where you are, you’re doing some experimenting, what have you. Remember, whereami? And you can see where you are currently.7:46 So now that we have our context back, let’s look at another command available to us. The step command. So looking at the documentation here, the step command, you can just say step by itself or give it a number. And this, the step command allows you to step in to the code. I kind of think about it like step into the execution points throughout the program.8:13 So you can step, you know, just one step, multiple steps, and gets that next, as they say here, next breakable point. If we do a step where we are right now, right now we’re on the zone 18 here. If we say step with no number, we see that we step to the next line here, but we start at the beginning of the line here. So right now, this current method has not been called and also, you know, the other half of this conditional has not been run yet either. So we’re kind of at the beginning of this line here before anything else happens.8:50 Now, if we step again, we will see that we end up in the current method now, okay? So now we did a step, we were right here. On line 19, the beginning here, we step into this call here to current. So it kind of steps to that next point of execution is how I like to think about this. So now we’re here, right?9:12 And so you can do things in here and play around and with this code here, if you wanted to, you know, you can just see like, oh, what does first up publish give me, you know, before you call this order and so forth, right? Now what’s fun about this is if you keep stepping at a certain point, at least in this case here with calling these class methods here, we step again, we see that we have now gone down into the source code for Active Record scoping named.rb, right? So now we’re inside some Rails source code here that we’ve stepped into by using debug and the step command to kind of navigate through the execution or breakable points, as they say, in the code here. So you can continue to walk this journey here and step and step and it’ll just continue to, you know, the next breakable points, the next point, so forth, if you want to, you know, carry on with your program, stop stepping like this and continue to say the next break point that you have set, if it, you know, falls in the execution path here or just continue your program and if there’s no other break points, just go until it’s done, you can type continue or con for short, but I’m just gonna do the long form here, continue, we’ll hit continue and then we see that our program goes all the way through, it grabs that latest event and we are now back at the IRB session, so we got out of the debug session and now we’re back at the IRB session. So I’m gonna get out of the IRB session here and hop back into the console actually and let’s hit our break point again and look at some other things.10:49 So here we are again, back at our break point, there’s also the next command. So if we look at the documentation there for next, contrast it to step where it’s stepping in, next steps over and it will resume the program until the next line. So let’s look at what happens using next here. So we’re on line 18 right here, if we step to next, we see that we are on the next line. Okay, this was similar to what we did with step, right?11:18 So we go to the next point right here, right the next breakable point and we’re at the beginning here, current has not been called nor has previous, but whereas last time when we hit step, we ended up in the current method, let’s see what happens when we hit next here. So here we see that it stepped over, right? This whole line right here, it went ahead and executed this line of code and then stepped to the next line. So we didn’t get down in all the glory details, if you will, of the current method and then into Active Record, right? We stepped over that whole line, we’ll have to do its thing and now on the next line, which just so happens to be for us, the end of this method definition here.12:05 All right, so I’m gonna get out of that session and then I’m going to hop back into our Rails console here and I’m going to hit our break point again by calling event dot latest, okay. And now we’ve been using binding.irb and then getting into the Ruby debug session by calling commands from the Ruby debug gem. So that’s one way to get to it. If you use binding.irb and then call one of the commands from debug, it will automatically run that command and put you into, or put that, put you into, it’ll automatically put you into that debug session and run that command that you used. If you don’t want to run a command and want to run a command and just get into the debug session, you can simply type debug, okay.12:52 And that will get you into the debug session. And if you type whereami, you’ll see that you’re still in that same spot in the code, right? We’re right here. Additionally, we see a list of some frames here and we’ll get to frames in a second. But that’s how you can get into the debugger through or the Ruby debug gem through IRB or binding.irb.13:19 Alternatively, if we get out of here, we have a few other options. So we can also do binding.b, okay. And if we hop into our console again, our Rails console, and we hit that break point created by binding.b, we will see that we immediately get dropped into a debug session. We skip the IRB part and go straight into the debug. So this is a method that comes from the debug gem.13:46 This is a short form of binding.break. So you can type binding.break, the full word break here, or you can just do binding.b for short. So that’s one way to go straight into the debugger session and not have to do binding.irb. But if, you know, binding.irb is the tough habit to break. If you have the debug gem in your application, you can go ahead and still get into it through binding.irb.14:11 Let’s look at another way to get into it real quick. So we can do bind dot IRB, binding.b, so forth, the other thing we can do is call debugger, just like this, okay. Now if we hop back into our Rails console, and then we do event dot latest, we see that we then hit the debugger here, and we, again, are dropped straight into a debug session. So those are your ways to get into the debug gem, right? Now, let’s look at the break command, ‘cause this one’s really cool.14:46 So with the break command just by itself, also it’s B for short, but I’ll use the long form here. Break by itself, if you hit enter on this, it will just return you a list of all the break points that you have set if you have them set. We currently do it right now. However, one cool thing here is that you can set additional break points from within this session here, right? So let’s say we wanted to add a break point after line 22 right here, okay?15:15 So on line 23, we want to add a break point. So what we can do is say break or B, and then simply 23, okay? And now you see that we get this output here, break point line, and what file it was in, and then what line, okay? So now if we type the break command here, we’ll see that same output. So we have one break point now set.15:37 And now if we wanted to jump straight from where we are, as long as the next break point that we set is in the execution path of our program, what we can do is we can type continue, okay? And it will execute from where we are in our program currently on the line 18 here, where this debugger set, and it will go through our program until we hit another break point, which in our case we will, because on the very next line here we call current, and we set a break point inside that method on line 23. So we hit continue here. We see that the code executes all the way through, and it stops right there at the beginning of line 23 here in current. So that’s really cool.16:16 You know, you can set additional break points and get to them, you know, as long as they’re in the execution path, you can continue on to them, and continue to hit those and add them as needed without having to leave this session, go back to your source code, put a new break point in where you want to, rerun everything, again, hit them all, and so forth. You can just stay, you know, in the same context here, not break your focus, and work through debugging something. You’re also not limited to setting additional break points in the current file that you’re in. So let’s look at that next. All right, so let’s say we’re debugging something around this method call here, this full method, right?16:56 Something’s going on, we don’t quite really know what, we just want to hit a debugger here and start debugging this thing, right? So we’ll drop a debugger there, and then let’s hop into our Rails console here, and then we’re gonna just say team, I was just gonna say team equals team.first to get started here, and then we’ll just say team.full, question mark, right? And so we hit our debugger break point, we’re in a debugger session right now, right? And now we want to add, we see that they call us this at or above capacity method on team users. So what we can do now is if we know, we know that this is in the team user’s file, we don’t know what line it’s on, if we knew what line it was on, one thing we could do is say, and I just know over here it’s on line 16, I’ve looked already, back over here, one thing we can do is add a break point to that file in that line, so we could say break, and then we need to pass the path to the file, this is going to be long, so bear with me, maybe I’ll fast forward here, app, models, team, user, and then colon 16, okay?18:02 So we’ve added a break point to that file and to that line, and now if we were to hit continue or cont for short, C-O-N-T, we hit insert here, we see that our program executed onward until we got to that break point here, that we set, right? Now, we probably could have used step to step through all this and get over here as well, but I just wanted to show an example of how you can set break points in other files. Now, one thing you can do that’s cool here is instead of this path here and passing a line number, you can just simply pass the class and the method and set a break point that way, so let’s look at how to do that real quick. All right, so back, hopping into another Rails console session here, let’s say team equals team.first again, okay? And then we’ll say team.full, we’ll hit that, debug a break point, and now we want to set a break point from where we are currently on this method over in the team user class file.19:05 So we could do that as we saw by passing the path to that file and the line number, but say we don’t know the line number, and we don’t want to hop back over to our editor, pop open that file, and add the break point there, ‘cause if we’re just gonna do that, we could just add the debugger while we’re right there and restart this whole process over, but we’re trying to keep our context here and not have to lose our focus on what we’re doing right now. We want to stay in the groove and on track and continue on down the path of trying to debug something here. So what we can do here, if we don’t know the line number, we can match against the class and the method name. So this being a class method here on the team user, we can simply say break on team user.at or above capacity, question mark, okay, and then we can hit enter on there and then we see that break point on a method was called and we see that it was added to the team user file on line 16, right, and as we saw previously, that was the exact line that that method is defined on. So now if we hit continue here or Kant C-O-N-T for short here, if we hit enter, our program will continue on until it hits that next break point.20:26 So we do that and we see there we are. We are at the beginning here of this method here. We’re inside the method body at the beginning of this line. All right, so let’s wrap up this video by looking at frames, okay. So I’m back in the Rails console here.20:39 I grabbed the first team. I’m just going to call a team.ful so it can hit our break point again. Okay, now we’re in a debugger session. So what we can do, as you can see right here, it gives us a showing of like the first two frames here and then it says in 27 frames and then it says use BT for all the frames. So the BT command will list out all of the frames that we have access to right now.21:06 So I’m going to just clear some space here in our terminal and then let’s run that BT command and let’s see what we get there. Also BT is just short for back trace. So as you can see here, we’re getting some auto completion. So you can type out the full thing back trace or BT to get this list here. And what we see here when we run that command is we get a list of all the frames that we have right now.21:31 It’s essentially a stack trace here, right? So this is the frame that we’re in where we hit our break point. And then this is all stuff that happened before we hit that break point, okay? So what we can do here is we can use these identifiers or ID numbers at the beginning here, the, you know, pound zero, pound one, or hash one, hash two. We can use these to jump straight to a frame or we can step one by one.22:03 So the way to, if we want to just go, this is going to be a little odd. If we’re looking at this list, we would think that we want to go down here, but really what you want to do is use the up command to go up one frame and just think about whatever current frame you’re on up will increment it to, you know, the next number larger, okay? So if we’re here and we want to go to main, we can simply type the up command. And now we see that our current frame is main right here. If we type L or list right here, we see some source code for the current frame, okay?22:39 Now, if we want to go back to the frame that we just came from, we can type down. So if we go down, we can see that we are now back here at this frame, and again, we can type list to see the source code and we see the source code right here for that current frame. Now, additionally, we can jump to a particular frame. So for an example, if we want to go to this frame here, frame 12, we can type either F and then the identifier number, which is 12 in our case, or the full command, which is frame, and then 12, okay? And now we see that we are in frame 12, which is this IRB file here.23:23 And if we type L or list, we can see the source code for that frame here. So this is a really cool feature. It allows you to go up and down the stack trace and check out things in different frame contexts. And again, once you’re in a frame, you can type list as I’ve been doing to see the source code. You can also type info to see the available, you know, local variables, instance variables, and other things that you have in this context available.23:52 So that’s really cool as well. You know, info is a great one. Also, there’s some arguments you can pass to the info command. You can find more info about that in the read me for the debug jam. But just for example, you can say info locals, and it will just give you back the local variables only and not all this other stuff.24:14 One last thing, if you’re in the debug session and you can’t remember commands or what you can do here, there is a help option. You can simply type help, and it will give you a list of all of the available commands that you have inside the debug session here with some nice little headers separating out the different sections of commands, breakpoint commands, control flow commands, and so forth. And additionally, as you see here, you can just type help, get the full list or help, and then some command and get help for just that command. So as an example, we say help maybe back trace, right? And then we see the information for all the back trace commands.24:53 So with that, I’m gonna wrap this video up here. I hope that this is, expose you to some new things that you have, new tools that you can utilize and have at your disposal to better assist you in debugging application errors. Also, this was kind of an introductory approach to this gem, there’s plenty more to read about in the readme, a lot of powerful things here. In my hope, don’t quote me on this, but I’m gonna try. My goal is to do a follow up video here, hopefully with someone from one of the maintainers of this gem, and see if we can pair on a video and maybe dig into some more of the advanced usage of this gem and provide that next level of debugging.25:47 So we’ll see what happens there. I’m gonna try my best to get someone from the team here to join me in a video call and dig into that stuff, but regardless, definitely utilize this gem. It’s great, it’s really powerful. And yeah, so with that, I’ll leave you here and happy debugging.

About this tutorial

This tutorial summarizes a GoRails screencast on debugging with the Ruby debug gem, presented by Collin. The screencast is the original work. GoRails publishes it, and the rest of the series, at gorails.com.