Setting Up a Debugger and Intellisense for Ruby on Rails 8 in Visual Studio Code/Cursor/Windsurf/etc
If you are confused by this guide or notice a mistake, please get in touch so I can fix it.
So, allegedly itâs very easy to set up a debugger for Ruby on Rails in Visual Studio Code. That was not my experience. Fortunately, after a few hours of messing around, I got it working pretty robustly with the following versions:
- Ruby on Rails 8.0.2
- Visual Studio Code 1.100.2
- Debug 1.10.0
- rdbg 0.1.0
- foreman 0.88.1
Debugger
It works somewhat fine if I directly start rails server
with rdbg, but itâs not robust and does not work with bin/dev
so you canât automatically run auxillary services, so, this setup launches bin/dev
in the background and then attaches.
You can also find all the files here.
Packages
gem "rdbg" # Ruby debug integration
gem "foreman" # Necessary for the procfile to work
Visual Studio Code
Install the Visual Studio Code rdbg Ruby Debug extension by Koichi Sasada.
Configuration Files
Update or create the following files:
.vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"type": "rdbg",
"name": "Run bin/dev & Attach rdbg",
"request": "attach",
"preLaunchTask": "runBinDev",
"localfs": true,
"localfsMap": "${workspaceFolder}:${workspaceFolder}"
},
{
"type": "rdbg",
"name": "Attach with rdbg",
"request": "attach",
"localfs": true,
"localfsMap": "${workspaceFolder}:${workspaceFolder}"
},
]
}
.vscode/tasks.json
Define the pre-launch task to start up the server using bin/dev
. Note that using this method, the server will keep running when you stop debugging, and you can re-attach by running the same debug configuration again.
{
"version": "2.0.0",
"tasks": [
{
"label": "runBinDev",
"type": "shell",
"command": "bin/dev",
"isBackground": true,
"problemMatcher": [
{
"owner": "custom-rdbg-task",
"pattern": [
{
"regexp": "^.*DEBUGGER: Debugger can attach.*$",
"kind": "info",
"file": 1,
"location": 1,
"message": 0
}
],
"background": {
"activeOnStart": true,
"beginsPattern": "^.*DEBUGGER: Debugger can attach.*$",
"endsPattern": "^.*DEBUGGER: Debugger can attach.*$"
}
}
],
"presentation": {
"reveal": "always",
"panel": "dedicated",
"clear": true
},
"group": {
"kind": "build",
"isDefault": false
}
}
// If you have other tasks, they would be here
]
}
Procfile.dev
Make sure the web:
line looks like this, with a call to rdbg, and leave the rest the same:
web: RUBY_DEBUG_OPEN=TRUE RUBY_DEBUG_NONSTOP=TRUE rdbg --command --open --stop-at-load -- bundle exec bin/rails server -p 3000
You can leave bin/dev
intact.
I am not sure how it would work if you had multiple processes you want to debug. You might be able to open both of them with rdbg and see if they attach to both simultaneously.
Testing
When you now go to the âRun and Debugâ tab, you can now select the âRun bin/dev & Attach rdbgâ and run it. After selecting it, you can also use the shortcut F5.
You can set breakpoints on the left side of the editor next to the line number, and enable automatically pausing on exceptions and errors in the bottom of the âRun and Debugâ tab.
As I said before, using this method, the server will keep running when you stop debugging, and you can re-attach by running the same debug configuration again.
Troubleshooting
Error during server startup when ârescue any exceptionâ or ârescue RuntimeErrorâ is enabled
I am also not sure why this happens, but it is harmless. You can either press continue until youâve skipped through all the errors, or untick those boxes for startup. If you know how to get around this, please let me know.
Cannot find the TCP port
You can try to explicitly define a port in the rdbg call in Procfile.dev
and the attach call in launch.json
In Procfile.dev
, add --port=12345
after the --command --open
part of the rdbg
command.
In launch.json
, add the following line to both launch configurations:
"port": 12345
Making sure the debugger gem is working
You can temporarily add an initializer, like debug.rb
, to the initializers folder:
if defined?(DEBUGGER__)
puts "Debugger support loaded successfully"
puts "Current directory: #{Dir.pwd}"
puts "Rails root: #{Rails.root}" if defined?(Rails)
# Force a breakpoint to check if debugging works at all
binding.break
end
If you launch with rdbg and it stops at binding.break, you can be confident that the debug and rdbg gems are set up fine.
Intellisense
There are two ways to set up intellisense in Visual Studio Code: Solargraph and Ruby LSP. Solargraph is older and more robust, but Ruby LSP is newer, faster, has more features and better Rails integration.
Solargraph
install the VS Code Extension.
Update your Gemfile to include the Solargraph gem:
group :development, :test do
gem "solargraph", require: false
end
Run this command to install the gem and generate the binstubs
bundle install
bundle binstubs solargraph
Create a .solargraph.yml
file in the project root:
include:
- "**/*.rb"
exclude:
- spec/**/*
- test/**/*
- vendor/**/*
- ".bundle/**/*"
require: []
domains: []
reporters:
- rubocop
- require_not_found
formatter:
rubocop:
cops: safe
except: []
only: []
extra_args: []
require_paths: []
plugins: []
max_files: 5000
Restarting should now start Solagraph. After restarting, check if you have any notifications in the bottom of your screen giving any solargraph issues. If it says the bin/solargraph
folder is missing, make sure to generate binstubs as per above. Hover over a function definition in a Ruby file to see if anything pops up with context or start typing and see if it starts auto-completing (manually trigger with ctrl+space).
Ruby LSP
I canât quite get this working in my setup, but it might help you on your way:
Install the VS Code add-on.
and add to your Gemfile
:
gem "ruby-lsp-rails", require: false
Restart Visual Studio Code, and open a Ruby file. There should be a {} Ruby
tab in the bottom right. Click this for the Ruby LSP status.
You might need to add the Ruby version manager manually to your .vscode/settings.json
file. Find the options here:
{
"rubyLsp.rubyVersionManager": {
"identifier": "auto/none/custom/asdf/chruby/rbenv/rvm/shadowenv/mise",
},
}
In my case, it could not find my mise install, so I had to set it manually (which I did globally):
{
"rubyLsp.rubyExecutablePath": "<path-to-your-ruby-as-I-got-from-"mise bin-paths">"
}
Typechecking with Sorbet and Tapioca
You can also set up type-checking for Ruby with Sorbet and Tapioca. Tapioca is still in alpha and itâs not working for me, but it should go like this.
Install the VS Code extension.
Add the gems to your Gemfile
:
gem "sorbet", group: :development
gem "sorbet-runtime"
gem "tapioca"
Then run the following commands:
bundle install
bundle exec tapioca init
bin/tapioca dsl
bin/tapioca gems
srb tc
If this doesnât work, you can check the sorbet and tapioca docs.
Subscribe to the Newsletter
Enjoyed this article? Subscribe to get notified when I publish new content.