Debugging a Rails App in Vim With Vimspector
Published: 2021-08-14 15:08:11

---
title: Debugging a Rails App in Vim With Vimspector
published: true
description: Debugging a Rails App in Vim With Vimspector
tags: 
//cover_image: https://direct_url_to_image.jpg
---

*Follow [@learnvim](https://twitter.com/learnvim) for more Vim tips and tricks!*

I recently published an article on Vimspector ([Debugging in Vim with Vimspector](https://dev.to/iggredible/debugging-in-vim-with-vimspector-4n0m)). There I covered different ways to run Vimspector for various Javascript environments. If you're a Rails developer like me, you may ask, "I'm sold on Vimspector, but how can I run it in Rails?"

To be frank, there are not a lot of resources online on how to accomplish this. After tinkering for a few days, I found a few setups that work on a basic Rails application.

I am not claiming that this is the foolproof way to debug any Rails application. There are rooms for improvement and exploration. But for starting out, this is sufficient.

This article assumes that you have had some experience with Vimspector. At minimum, you need to know how to step into, step over, and step out of breakpoints. You also need to know how to launch and restart Vimspector. If you don't, please read my previous article first.

## Create a Basic Rails App

I am a huge fan of practical learning. I believe you'll get far more mileage if you actually do the steps as you are reading this article. So for the sake of hands-on approach, let's create a brand new Rails app. Don't worry, it should take less than 5 min.

Create a new Rails app:

```
rails new hello
```

Create a controller:

```
rails generate controller Says hello
```

Let's go to the controller and write up some codes. Inside `./app/controllers/says_controller.rb`, modify the `hello` action:

```
class SaysController < ApplicationController
  def hello
    @time = DateTime.now
    @greetings = "Greetings"
  end
end
```

Modify the `hello.html.erb` file:

```
<h1>Says#hello</h1>
<p><%= @greetings %></p>
<p>It is now <%= @time %></p>
```

Excellent! Let's quickly test if the Rails app is running properly.

```
rails s
```

Visit http://localhost:3000/says/hello. You should also see the values of the `@greetings` and `@time` instance variables.

### Adding Important Gems

Vimspector isn't a debugger. It's a "middle-man" that talks to a debugger. Vimspector provides a standard protocol to communicate with different debuggers. With Vimspector, you can communicate the same way with a Node debugger, Python debugger, Go debugger, etc.

For Vimspector to work with Ruby, you need to install a Ruby debugger. We will use [ruby-debug-ide](https://github.com/ruby-debug/ruby-debug-ide).

In addition, you also need to install `debase` ([source](https://github.com/rubyide/vscode-ruby/blob/main/docs/debugger.md)). Add these two in your gemfile (in a real project, you probably want to put them inside the `group :development, :test do ...` block)

```
gem 'ruby-debug-ide'
gem 'debase'
```

## Vimspector JSON

Create a `.vimspector.json` at the Rails project root. Inside it:

```
{
  "configurations": {
    "rails": {
      "adapter": "cust_vscode-ruby",
      "default": true,
      "configuration": {
          "name": "Debug Rails server",
          "type": "Ruby",
          "request": "launch",
          "cwd": "${workspaceRoot}",
          "pathToBundler": "/Users/iggy/.rbenv/shims/bundle",
          "pathToRDebugIDE": "/Users/iggy/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/ruby-debug-ide-0.7.2",
          "program": "${workspaceRoot}/bin/rails",
          "args": [
              "server"
          ]
      }
    }
  }
}
```

Note that you have to update `pathToRDebugIDE` and `pathToBundler` with your own paths. I'll explain below.

### Bundler, Debugger, and Adapter

There are three things that you need to provide Vimspector with:

1. The path to bundler.
2. The path to the debugger.
3. Which adapter to use.

To get the path for `pathToBundler`, run: 

```
which bundler
``` 

In my case, it returns `/User/iggy/.rbenv/shims/bundle`. Use whatever path your machine uses.

Assuming you have installed the ruby-debug-ide gem via your Rails' Gemfile, to get the `pathToRDebugIDE` path, run:

```
bundle show ruby-debug-ide
```

In my case, it returns `/Users/iggy/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/ruby-debug-ide-0.7.2`. Use whatever path you see.

Finally, recall that Vimspector requires a special adapter for each language / environment you use (in my previous article, I installed  adapters - also known as "gadgets" - for node and chrome). Since we're debugging a Ruby framework, we need a Ruby adapter.

### Adding a Ruby Adapter

If you look at the Vimspector config file above, you'll see:

```
"adapter": "cust_vscode-ruby",
```

Unfortunately, Ruby is not in one of the [supported languages in the Vimspector page](https://github.com/puremourning/vimspector#supported-languages) (*darn it!*). Don't worry, if you dig the Vimspector repo deep enough, you will find instructions on how to "install" a Ruby gadget there.

Here's [the page](https://github.com/puremourning/vimspector/wiki/languages#ruby-gadget-installer-file) with information for languages not officially mentioned in the README. If you scroll down, you'll find an instruction for Ruby. 

Follow the instruction on the [introduction section](https://github.com/puremourning/vimspector/wiki/languages#introduction)

1. Inside the Vimspector *directory* (in my case, it is in `~/.vim/plugged/vimspector/gadgets/custom/cust_vscode-ruby.json` - yours could be in a different directory depending on what plugin manager you use), add a custom  json file for your language.
2. Run `./install_gadget.py --upgrade`. Vimspector should install some files from `vscode-ruby`.

Phew! We are done with the preliminary setup.

If you're still curious what just happened, here are a few pages to read:

- [Ruby gadget installer](https://github.com/puremourning/vimspector/wiki/languages#ruby-gadget-installer-file)
- [VSCode-Ruby Debugger](https://github.com/rubyide/vscode-ruby/blob/main/docs/debugger.md)

### Program and Args

Let's take another look at a section inside the Vimspector config file:

```
"program": "${workspaceRoot}/bin/rails",
"args": [
  "server"
]
```

Recall from the previous article, `program` is the program that Vimspector will run when you tell it to launch something and `args` is the argument that gets passed to `program`.

When running a rails app, you would (usually) run `bin/rails server`. The config does exactly that.

## Running the Vimspector

Now we are ready to run Vimspector. Our config is set to `launch`, so do not run `rails s` from the terminal. We will run it from the debugger.

Go to the `says_controller.rb` and add a breakpoint on `@time`:

```
class SaysController < ApplicationController
  def hello
    @time = DateTime.now # add a breakpoint here
    @greetings = "Greetings"
  end
end
```

Excellent. Now here comes the moment of truth - let's launch Vimspector!

Wait a few seconds, you should see on the `Console` window that Vimspector is launching a Rails app.

Now, visit http://localhost:3000/says/hello. The app should pause.

Check your Vimspector. You should see it paused at the breakpoint.

![Rails Vimspector Launch](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4h9k7qgp4wzm6kf59202.png)

If this is what you see, congratulations! You've successfully launched a Rails debugger - from Vim!

From there, you can step into, step over, and step out of different lines of code.

## Attach Vs Launch

There are two ways you can run Vimspector: attach and launch. The former attaches the debugger into an already running process. The latter launches a process from the debugger.

The Rails example above is an example of launch, as it launches a Rails process directly from the debugger. Theoretically, you should be able to perform either attach or launch.

### Attaching a Debugger to a Rails Server

You've seen how to launch a Rails app from Vimspector. Let's see how you can attach Vimspector to a Rails process.

First, modify our `.vimspector.json` file:

```
{
  "configurations": {
    "rails": {
      "adapter": "cust_vscode-ruby",
      "default": true,
      "configuration": {
          "name": "Debug Rails server",
          "type": "Ruby",
          "request": "attach",
          "cwd": "${workspaceRoot}",
          "remoteHost": "0.0.0.0",
          "remotePort": "1234",
          "pathToBundler": "/Users/iggy/.rbenv/shims/bundle",
          "pathToRDebugIDE": "/Users/iggy/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/ruby-debug-ide-0.7.2"
      }
    }
  }
}
```

Here are the changes:
- `request` is now `attach`.
- We added `remoteHost` and `remotePort`.
- We removed `"programs"` and `"args"` (they are unnecessary for attach).

The `remoteHost` and `remotePort` are the IP address and port number that we will be running the debugger on. The host is set to `0.0.0.0` and the port is set to `1234`. These numbers will make sense in a little bit.

Once your `vimspector.json` file is configured, let's run the app. Instead of running the regular `bin/rails s`, run:

```
rdebug-ide --host 0.0.0.0 --port 1234 --dispatcher-port 1234 -- bin/rails s
```

This will launch the `ruby-debug-ide` program installed earlier. Note the host and port numbers: we are running the debugger on host `0.0.0.0` and port `1234` in addition to running the rails server.

Next, add the breakpoints inside the `says_controller.rb` file, then launch Vimspector. Since we are running Vimspector on attach mode, it won't launch a Rails server this time. Head to the page related to this controller: http://localhost:3000/says/hello. Watch your Vimspector pauses at the breakpoint(s). 

![Rails Vimspector Attach](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hc1gtnt8hxs19brnu45k.png)

Sweet chocolate pancake! Super cool, isn't it? Well, this also concludes this article.

# Conclusion

Congratulations! You've successfully debugged a Rails app. You are one step closer from becoming a supreme master developer.

There is still much to explore about Vimspector and Rails applications. There are different settings, environments, and configs that I don't mention in this article. Experiment. Share this article. Let me know how you do things differently.

In the end, I hope that this article has given you a good place to start. Happy Vimming!