Transcript

If you use VS Code for Ruby development or you’re looking for ways to improve your debugging workflow in your Rails app, you’ll want to check out this screencast.

There have been a ton of quality of life improvements to Ruby over the past few years, and one of the headline features of last year’s 3.1 release was a dramatic overhaul of the long-neglected lib/debug.rb as a new gem debug.gem, led by Koichi Sasada.

Aside from providing a more pleasant, feature-rich command line interface with many features you know and love from pry and Byebug, the new debug gem can also communicate with GUI front-ends like VS Code. This allows you to attach VS Code’s IDE-like debugger interface to any running Ruby process without interfering with your shell’s STDIN and STDOUT.

This is made all the more important if you’re starting a new app in Rails 7 and using esbuild, because Rails will generate a new bin/dev script that combines your Rails server, CSS watcher, and JS bundler into a single process managed by foreman. This is really convenient for running your Rails app with a single command, but it’s a nightmare for trying to interrogate the system with an interactive debugger.

But it turns out, it’s not a nightmare! It’s actually pretty awesome!

As this screencast shows, you can have the best of all worlds if you launch your Rails process with the new debug gem’s rdbg command and then attach a remote debugger separately. Not only do you get a single command to run your collective development servers, you can easily set breakpoints and catch them right in your editor!

A couple other resources mentioned in the screencast:

00:00
(upbeat tune playing)
00:03
- I am starting to play with VS Code, Visual Studio Code
00:06
and getting my Ruby on Rails configuration
00:09
just how I like it.
00:10
And one thing that I came across was that
00:12
the debugging story has gotten very, very, very, very good
00:16
in Ruby 3.1, where up until this point
00:19
it actually lagged behind most other languages,
00:22
of course being super dynamic interpreted language,
00:24
you would expect that to a certain extent,
00:28
but Koichi Sasada in particular,
00:30
has really put in a lot of work
00:31
to modernize the Ruby builtin debugging facilities
00:36
as well as a gem called debug
00:39
that will allow us to actually use
00:41
the native VS Code debugger to debug our stuff.
00:45
And I just discovered this yesterday
00:46
and I realize a lot of people probably don't know this yet.
00:48
So I'm going to walk through a little bit
00:50
of like the Rails, so using Ruby on Rails 7.
00:53
A little bit about like why debugging has gotten trickier
00:56
even though it's gotten more advanced for Rails 7,
01:02
as well as how to wire everything up to VS Code.
01:05
So you can use like a nice vanilla out of the box
01:07
Rails 7 installation, and also take advantage
01:10
of the new fancy debugging facilities
01:13
that are much more native feeling in something
01:15
like VS Code and, and surely other, you know, kind of
01:18
like more batteries included editors like RubyMine.
01:21
All right, So we're gonna start
01:23
with just making a new application, I suppose.
01:29
So let's go into a code directory
01:31
and I'm gonna make a new,
01:35
well, first of all let's check our versions, right,
01:36
because time keeps moving.
01:41
I'm not great at typing.
01:42
Okay. So we're on Ruby 3.1.2 Rails 7.0.3.1.
01:46
We're gonna make a Rails new app.
01:48
We're gonna call it rebug.
01:50
And this time we're gonna use esbuild as opposed
01:53
to Webpacker, or as opposed to, you know, Sprockets
01:57
for a JavaScript concatenation.
01:59
And we're also gonna set it up to say
02:00
hey we wanna use tailwind for CSS.
02:04
We're not gonna actually write any tailwind today
02:05
but I wanna create an environment and then,
02:08
oh yeah and Propshaft as opposed to Sprocket.
02:10
So, so Propshaft is a more modern, more live,
02:14
simple
02:16
asset
02:18
pipeline
02:19
Asset manager to like do the stuff
02:21
with the application dot CSS and, and
02:23
application dot JS without necessarily like considering
02:28
all the stuff Sprockets had to do with like stuff
02:31
like actively transpiling CoffeeScript and SAS.
02:34
So it's just a simpler one.
02:36
When we do a new application this way
02:39
it's actually going to, by default,
02:41
create a procfile dot dev file.
02:44
And when it creates that procfile dot dev,
02:46
that is like going to be actually invoked whenever
02:49
we say bin slash dev.
02:51
So you might be familiar with over the last many years,
02:54
running your Rails app in one terminal window,
02:56
and then your Webpacker in another one,
02:59
because it's kind of gotten outta hand
03:01
You can, you can see the procfile dot dev
03:05
pop into rebug,
03:08
You can take a look at it.
03:09
So here we have now a web process, a JavaScript process,
03:13
and a CSS process, cause we're using JS bundling,
03:15
CSS bundling, and then of course
03:18
you had to run your Rails server.
03:19
And so that's just like, keeping three terminals open
03:20
is too much and you can
03:22
of course you can still go and run Rails s
03:25
and you can you can run yarn build and so forth,
03:28
but you can also run this new bin dev
03:31
that's built in for you as a bin stub.
03:33
And so it'll just
03:35
All it does is make sure that that foreman is installed
03:38
and then it'll start foreman, nothing fancy.
03:40
So if we run bin dev like that
03:41
you'll get some color coding
03:42
and it'll run all three of these things at once.
03:45
All right.
03:46
So that's our application, I suppose if I just run it now
03:50
and I let's say open up,
03:58
Neat. All right,
03:58
So I got a Rails thing.
04:02
I'm running my Rails
04:03
and now I'm gonna start writing some code.
04:05
And like I said, I'm getting into VS Code.
04:07
So we're gonna open up VS Code here.
04:10
All right, so I'm in VS Code,
04:11
everything is new again, nothing's committed.
04:13
So we're just gonna ignore the commit status
04:15
for everything today.
04:16
And we're gonna make just a couple adjustments.
04:19
We're gonna start writing some code here.
04:21
So I'm gonna get rid of the default Rails stuff.
04:24
And I'm gonna say
04:25
we're gonna cover resources called things.
04:27
And the root of our application is gonna be things index
04:31
which is gonna necessitate a things controller
04:35
which we can take a look over here.
04:38
We can say, Hey, all right,
04:39
So things controller dot RB,
04:42
boom.
04:43
And then, I'm still getting used to the VIM emulation
04:47
inside of this thing, it's pretty good. Fine.
04:51
I don't love it, but all the other kind of perks
04:54
are enough to keep me interested.
04:57
All right.
04:58
Let's see.
04:59
Okay. So now I've got a things controller
05:03
things index is my root,
05:05
and I just wanna render
05:08
some JSON.
05:09
So let's say like
05:12
now
05:14
and actually let's make a variable
05:16
so we have something to debug.
05:18
So now equals time dot zone dot new
05:25
or time dot zone dot now?
05:27
I always forget. Yeah. time dot zone dot now.
05:28
Okay, so then we're gonna render some JSON now got it.
05:31
And the standard of course
05:32
is gonna remind me to remove the white space.
05:35
All right.
05:36
So if I look at local host 3000, now I get my,
05:41
you can see it up in the corner, the JSON.
05:43
All right, neat.
05:44
So let's say that I am in the, you know
05:49
I want a debugger.
05:50
Now you might be familiar with pry or byebug,
05:53
in Rails 7 They changed the default,
05:55
and maybe this is starting with 3.1,
05:57
It would make sense if it was,
05:58
they changed the default to actually debug here.
06:00
So you can see there's a whole guide
06:02
on the changes to debugging.
06:04
Here's the debug gem and which platforms it supports.
06:07
And so we're gonna have a different set of commands now,
06:11
you can still use, Binding, IRB and other stuff,
06:14
but we're gonna just say
06:15
debugger here to put in a debug point,
06:17
and then gonna take a look at our terminal.
06:21
Now, if I refresh the page at this point,
06:23
I do indeed catch the debugger.
06:24
You can see the debugger here,
06:26
you can see the nice, like, where am I?
06:28
But like foreman and foreman-like stuff like
06:31
I imagine Hivemind, Overmind and similar
06:34
process splitting, aggregating tools
06:36
for running multiple processes in one shell is not designed
06:40
for like capturing standard in particularly gracefully.
06:42
So if I wanna type like, okay, so now,
06:45
oh well that doesn't do what I want, really.
06:47
And if I say C and I run, will it actually continue?
06:52
Like maybe not continue command completed, okay, cool.
06:57
And so it's just like not a particularly graceful way
07:00
to be like, all right.
07:00
So LS now.
07:04
And it didn't actually,
07:05
it's like list command.
07:06
It's clearly not picking up all
07:08
of my keystrokes in order, which is to be expected.
07:11
I mean, that's not,
07:13
this is not like the most delightful debugging experience.
07:16
So of course like what I could do
07:19
if I killed everything,
07:22
Okay, cool.
07:23
So what I could do of course is I could just like
07:25
go back to the, the good old days of running bin Rails S
07:28
and I could, let's say load this page again.
07:32
Now I get my debugger and I can, you know, if you've
07:34
if you used pry, there's a new outline command
07:38
that'll give you all of the methods
07:40
just like pry's LS command, which is really
07:43
like my favorite reason for using pry's to figure out
07:45
you know, like what are the methods on this thing?
07:48
And LS is indeed
07:51
an alias of outline for people used to that,
07:53
but it just like RDBG
07:58
allows you to do like, you know
08:01
break point debugger commands, like continue
08:05
and c, even a queue for quit.
08:08
You can get these little things, like step over or step.
08:13
I don't know if step in or step over is a default for step.
08:16
So that's like, neat.
08:18
You can, you can do all that stuff.
08:19
You can look at variables.
08:20
You can of course, like ask questions, like now dot day
08:23
that's just like the traditional debugging facility.
08:25
But of course we lose the procfile running everything
08:28
for us, and we'd be going back to three.
08:29
So like, what I wanna avoid, right,
08:31
Whenever I'm programming is I wanna get fast feedback
08:33
and I wanna have a quick way to hook
08:35
in to a particular thing without necessarily
08:37
going over to another terminal and
08:39
killing all my servers and then starting all over again
08:41
and then trying to get everything into the same state.
08:43
So what I want instead is to make it really easy
08:45
just attach and detach a debugger
08:46
from whatever my process is, and I wanna run the process
08:48
in the most convenient way possible.
08:50
So here we go.
08:50
So we're gonna exit.
08:53
alright, we quit our server.
08:55
We're we're not gonna run things that way anymore.
08:58
And instead,
09:00
what we can do is we can think
09:02
about this new tool called RDBG
09:05
which comes along with the debug gem,
09:09
which Koichi has written, which is sort of inheriting
09:12
the old lib debug from Ruby.
09:17
And we can actually say, let's see RDBG
09:19
and you can just give it tac c
09:21
and then you can give it a command
09:25
and what it'll do is it'll actually
09:27
launch whatever your command is
09:29
but first pause and attach to the debugger to it.
09:33
And we can just say, continue here.
09:34
And it's just running our service, we can refresh the page,
09:37
we catch the thing.
09:38
This is not that dissimilar, of course
09:40
from just like writing debugger in there.
09:42
But what's interesting is like
09:43
if you learn this command a bit,
09:47
you can see how
09:49
you can start to build up what you might be interested in.
09:51
So we can say like tac end for example
09:54
and it'll run nonstop.
09:57
It'll just run for us
10:00
it won't do that initial pause.
10:02
Great.
10:05
Okay. Quit.
10:06
Okay. And then you can also tell it to open a particular
10:12
front end for the debugger.
10:14
And now by default, that front end is RDBG.
10:16
That's like what we've been doing, now, instead
10:19
what we're gonna do is we're gonna actually like launch this
10:21
with VS Code.
10:24
We're just gonna take a couple steps because by default,
10:26
it's not gonna just magically work
10:31
because we don't have any sort of like awareness of
10:34
the Ruby debugger in VS Code.
10:36
So what we're gonna do is we're gonna go over
10:38
to the extensions world, We're gonna say
10:41
search for VS Code RDBG and hope that we find it.
10:46
There we go.
10:47
So Koichi also wrote this VS Code RDBG Ruby debugger,
10:51
We're gonna install it here.
10:56
And because I don't trust VS Code just yet,
10:58
even though it's all JavaScript and cool,
11:00
I am going to quit out entirely.
11:04
Quit that too.
11:07
And I'm gonna run
11:09
this again.
11:10
It's going to attach VS Code here
11:12
I can see I'm attached now to a VS Code debugger,
11:19
and if I refresh the page, I'm here, I'm in the debugger.
11:22
Now I'm again, I'm in an arbitrary window though.
11:24
I'm not in like my application window right now
11:27
but I can see like, okay, cool.
11:28
I have, now I've got like a step a debugger.
11:31
These commands up here I can like
11:32
step over a line and so forth.
11:34
I also have this debug console in addition to my terminal.
11:36
So I could run the terminal here,
11:37
but you can see I'm like in this variable
11:40
like folders like this Tempter.
11:41
So it's not quite perfect, but I can get in like this.
11:44
Now, if I wanted to fold this into my application
11:49
what I could do instead is I could actually wire this
11:52
in as a launch configuration
11:55
to attach manually to a running process.
11:58
So let's try doing that, it's a little bit finicky,
12:00
I haven't figured out the exact order of what to do
12:03
with this stuff, but we're gonna quit out again.
12:07
I'm gonna go here, we've exited that,
12:10
I'm going to run code period
12:11
to open up Visual Studio Code to a particular place.
12:14
I've got this extension now down here, the VS Code debugger,
12:18
I'm going to now make a launch config.
12:23
I'm gonna do this.
12:24
Now you can see it's got two different launch configs
12:27
by default, the debugger, the current file with RDBG.
12:30
I'm not gonna use that one today,
12:31
That's actually more self explanatory,
12:35
but I do wanna be able to attach with RDBG.
12:39
And so you can see this right here.
12:43
And so what I'm gonna do
12:46
is I'm going to just
12:47
from the terminal window here,
12:51
sticking in the terminal.
12:54
I'm going to run
12:58
that same command that we just had over in my terminal.
13:01
I'm starting to get at more and more stuff into
13:03
VS Code in the interest of living the, the sweet IDE life.
13:09
Okay. So I'm gonna run that here.
13:14
Now I'm running and I can run attached with RDBG.
13:20
Okay. Now I refresh the page
13:22
and I am inside now, my actual like, you know project.
13:27
So if I'm looking at the Explorer view, it's synced up
13:29
with where I am in my source code.
13:31
And I'm right at that debugger
13:32
and I can still type into my debugger console.
13:35
So that's pretty slick.
13:36
I can hit play and I can continue.
13:38
In fact, I can remove the debugger now
13:40
that I'm like, sort of attached to a session
13:45
or I know how to attach to a session, I can actually
13:48
create a break point here by just making
13:51
a little red dot here in the gutter.
13:53
And now when I visit the page,
13:58
it should have caught that,
14:02
it didn't catch that.
14:04
Okay. So why isn't the debugger going?
14:08
Did I, no, I got a break point.
14:12
What did I do wrong?
14:21
Restart.
14:27
That probably was the wrong thing to do.
14:29
Did it quit? No.
14:31
Cannot find attachable Ruby project.
14:32
Okay. So I'm gonna try that one more time.
14:35
That's surprising.
14:36
It's worked every time until I do it on video, naturally.
14:40
Ah, shoot.
14:44
Oh yeah, I didn't actually attach I that time.
14:47
Okay. So I'm attached now.
14:49
I got my debugger.
14:51
I refresh, cool. And I'm here.
14:54
And if I refresh again, it should reattach. Okay. So
14:59
it works usually,
15:01
don't feel bad if things don't work the first time for you,
15:04
the biggest, most fun part of being a programmer
15:07
is the banging your head up against a wall
15:08
and then getting different results
15:09
each time you try something.
15:12
All right.
15:13
So now I can debug whenever
15:16
and I create little break points.
15:19
I can enable disable the break points
15:21
this tiny little view down here, itty-bitty guy.
15:26
I'll see the break point there
15:27
and I can enable disable it from a central place.
15:31
Of course, you know, like if you're familiar
15:32
with step debuggers, all of the step commands are up here
15:36
and you can also kind of expand here
15:37
and look in at whatever your state is.
15:39
There's nothing interesting here
15:40
cause I'm just like on the top level a controller
15:42
and I don't have any of my own code,
15:43
but if you're in like a class
15:44
and you had like, you know, state
15:45
or you had other things going on
15:46
or you had a big call stack
15:48
you'd have interesting stuff to look at.
15:50
And of course the call stack here
15:51
is split up because Puma by default has a gajillion servers.
15:56
Okay. So we've got, now we've made a lot of progress.
15:58
We've got a new Rails application.
16:00
It's using
16:02
this new debug gem.
16:04
We've got the debug gem looking at VS Code
16:07
and we're almost where we wanna be
16:09
except we're still just running bin Rails S
16:11
to get a debugger, which is not quite where we wanna be.
16:15
We wanna be running that new bin dev command
16:17
which is gonna run foreman.
16:18
So that's gonna require us to go
16:21
and take a look at procfile dot dev.
16:25
And here we can actually just put exactly what we had
16:28
from our terminal using
16:30
RDGB tac n
16:33
tac tac open vscode
16:37
and then leave that remaining tac tac
16:41
and a space
16:42
so that the command that runs is this right here.
16:45
Now this is like a generated file, but it lives in the
16:48
in the root of the project,
16:49
and so we can safely edit it
16:51
and just know that if like we do rerun, a Rails generator
16:55
we might have to like, you know
16:56
deal with this in version history.
16:57
But like, this is ours, we can do this if we want.
17:00
Now it says VS Code here,
17:03
I can show you a trick later to like
17:05
extract that away into an environment variable
17:07
because maybe not everyone on your project uses
17:08
VS Code and still wants to run bin dev, but let's go ahead
17:11
and try running bin dev here in our terminal.
17:14
So now we're starting three different processes up
17:17
now with this debugger, like I just accidentally showed you
17:21
if you refresh the page, it won't catch
17:23
by default because we've not attached a debugger to it.
17:26
But with this break point,
17:30
we can, you know, launch and there's a way to launch control
17:33
I think is the name of the extension here. Launch.
17:39
Launch configs.
17:41
This, this little relatively unknown extension
17:43
will allow you to make keyboard shortcuts
17:46
for launch configs and so I would probably
17:48
just bind this to something like command shift,
17:53
alt R or D or something.
17:55
But anyway, I'm gonna run this now,
17:58
when I run it, it's gonna be running, I refresh
18:02
and now I've caught my debugger
18:03
and you can see I've done that
18:04
without goofing up all of the output in the main foreman.
18:09
In fact, I hit play, you can see the debugger got connected,
18:12
but then it just finished the request
18:13
standard in standard out didn't get all goofy
18:15
and wonky in the process.
18:17
So that was pretty cool.
18:19
We got through a lot, the little trick that I use
18:23
for avoiding having like any editor specific stuff
18:28
in my procfile is you can use an environment variable
18:33
instead, you can do like an expression here
18:35
because this is ultimately just gonna be processed
18:37
by your shell.
18:39
You can say RDBG, This is a custom variable that you can own
18:43
that you can create, and then you can set a default for it.
18:46
So maybe you just make it RDBG by default,
18:49
which of course as we've shown, is not particularly
18:51
user friendly when you're running via foreman,
18:53
but it's the most obvious thing.
18:55
And so now when we run it, I've actually already set
18:59
that variable in my profile as a user.
19:02
So if I like, you know, echo this out
19:03
you can see it says VS Code.
19:05
And now I can run bin dev, when I run bin dev.
19:08
And this is a second verse saying, this is the first kind
19:12
of thing I've attached
19:14
with RDBG,
19:16
I'll get used to that eventually
19:18
I'll refresh this page
19:19
and then you can see I'm caught again.
19:21
So that way I can when time comes to commit all this to git
19:25
I don't have to have VS Code,
19:26
the word VS Code or any one particular tool anywhere
19:29
in my, you know, git repository, it can all be agnostic.
19:32
And yeah, so like this is pretty darn slick,
19:35
in my opinion, like, you know it gets you that kinda like,
19:38
you know, neat introspective
19:41
IDE feel without any of the gross like lock in
19:45
and proprietary-ness
19:47
or slowness, it's actually like really fast.
19:49
So kudos to Koichi and the rest of the Ruby core
19:53
and Ruby committers team.
19:55
Ruby 3.1 is just like Ruby 3.0 before it, it keeps coming
19:59
with like more and more quality of life stuff,
20:01
and so if you haven't upgraded a 3.0
20:04
or to 3.1, when you do I strongly encourage you to check out
20:08
a lot of the talks from the last couple years of RubyKaigi,
20:11
RubyKaigi takeout, they they've done
20:13
lots of great videos in English
20:15
about all of the improvements that they've made to the
20:21
IRB, to the
20:24
read line, input output stuff like to
20:25
make the interactive shell really useful,
20:27
and now this RDBG stuff supporting any arbitrary
20:30
debugger front end is this really slick.
20:31
So thanks again to our friends
20:34
on the Ruby core team and, and the other Ruby
20:36
committers who who've made this just so great.
20:40
So I'm really excited to like, you know
20:41
start developing Rails this way and having like a
20:44
a nicer debugger story than I've had before.
20:46
Cause it ultimately just means faster feedback
20:48
and getting answers to the questions
20:50
that I have for my computer faster.
20:51
So check it out and I hope you have a great time.
20:54
Thanks for watching.

Justin Searls

Person An icon of a human figure Status
Double Agent
Hash An icon of a hash sign Code Name
Agent 002
Location An icon of a map marker Location
Orlando, FL