Getting the most out of Solargraph in a Rails project
Ruby’s LSP story outside of IDEs like RubyMine or Komodo Edit is somewhat tricky and hard to set up. There are a variety of different gems out there, many of them unmaintained, and several VSCode extensions. Which ones should be used? Which of them even work? In this post, we’ll go over how to set up Solargraph with VSCode and how to get the most out of it with YARD documentation in a Rails project.
Setup
In a new Rails project add the Solargraph gem to your Gemfile. Ideally in the development group. if you already installed Solargraph locally, that’s fine. Still, add this line to the Gemfile.
gem 'solargraph', require: false, group: :development
Then, run bundle install and create a binstub for Solargraph using bundler (you may need to use bundle exec)
$ bundle install
$ bundle binstubs solargraph
Now create the configuration file for Solargraph
$ bin/solargraph config
You’ve now set up the project so that Solargraph can start indexing it. Solargraph will not know much about the gems we have installed or Rails. Run the yard gems
command to create YARD documentation for your installed gems. This will let Solargraph know about your installed gems including Rails. it won’t be helpful yet though.
VSCode isn’t aware of Solargraph yet so it can’t tell you anything about the code it can see. You can install the VSCode extension now for Solargraph and configure it for our project. Find the extension here
Configuration
You should have a file in the root of the project from the previous steps called .solargraph.yml
if you open this file, it should look like this:
---
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
The documentation on the Solargraph website covers most of what is in here. The bits that are going to change are the require
,include
and, plugins
keys.
Before you change anything, configure the VSCode extension so that it’s aware of our Solargraph installation and can display things to you about the code it can see.
You should tell the VSCode extension to use the binstub. This is best because if the project is opened on a new machine, you won’t need to change any settings for the extension. Alternatively, you can also use the useBundler setting if there are issues with the language server starting.
With this done, you should now see code suggestions for the Core and Std library.
Now that Solargraph understands your project and provides us with Core and Std completions, it’s time to teach it about Rails so it can be really useful. As mentioned, you need to change a few keys in the .solargraph.yml
file.
include:
- "app/**/*.rb"
- "config/**/*.rb"
exclude:
- "spec/**/*"
- "test/**/*"
- "vendor/**/*"
- ".bundle/**/*"
require:
- actioncable
- actionmailer
- actionpack
- actionview
- activejob
- activemodel
- activerecord
- activestorage
- activesupport
plugins:
- solargraph-rails
domains: []
reporters:
- rubocop
max_files: 5000
The include
key tells Solargraph to watch certain directories. As this is a Rails app, it only needs to watch theapp
directory. Theconfig
directory was added as you’ll need it to help Rails with things it cannot see from classes and modules, like DSLs.
The require
key has the paths we want Solargraph to implicitly require for us in our files. This means that it will offer suggestions for the required files. Useful as Rails has a lot of different helpers for its classes.
Finally, the plugins
key has the solargraph-rails
plugin. Add this to your Gemfile in the development group, like the Solargraph gem.
gem 'solargraph-rails', require: false, group: :development
When we add the plugin to our .solargraph.yml
file, you’ll need to restart Solargraph. You can do this via the command palette. With these steps completed, you should have pretty good suggestions for ActiveRecord models and the routes.rb
file. But, there are some things Solargraph will not know about, for example, any controller DSLs added by gems or transitive dependencies. To add these in, we need a file with some YARD documentation.
YARD is a Ruby documentation tool. it’s widely used and powers lots of Solargraph’s features. Solargraph has slowly been adopting RBS more and more (RBS is a way to describe types and classes in Ruby code). Previously, as part of set-up, you needed to download a core via the gem and then use YARD to generate documentation to have Solargraph understand the Core and Std libraries and other gems. Long story short, this is no longer necessary as Ruby has adopted RBS type signatures in the Core and Std libraries that Solargraph now uses. If a gem doesn’t have RBS type signatures, Solargraph will fall back to using YARD.
Create a file called definitions.rb
in the config
directory and copy this gist into the file (it’s from the Solargraph documentation).
This file is no longer required with the Solargraph-rails plugin added to the .solargraph.yml
file. But, it’s useful to have in case you need the gems that add DSLs to have suggestions (the domains
key in the .solargraph.yml
file can handle these, but it’s somewhat temperamental).
Instead, use the @!parse
tag from YARD to tell Solargraph about a module that is patched into ActionController at run time.
# @!parse
# class ActionController::Base
# include ActionController::MimeResponds
# extend ActiveSupport::Callbacks::ClassMethods
# extend AbstractController::Callbacks::ClassMethods
# include Sorcery::Controller::InstanceMethods
# ^^^^
# this lets us see the Sorcery controller methods in our completions
# end
Sorcery is a very useful and focused auth gem that can seamlessly integrate with Rails. It adds some methods to ActionController at runtime that Solargraph simply cannot be aware of. The @!parse
tag causes Solargraph to parse the code within it without executing it. This lets you tell Solargraph about the dependency and the methods contained within.
What next?
You’ve set up Solargraph in VSCode and configured it to give good code suggestions on most of the Rails code you can encounter. You also have a way to patch modules that should be available in classes that Solargraph isn’t aware of.
Solargraph can work out return types from methods and instance vars with the @param
tag. Let’s take this snippet from config/initializers/inflections.rb
this code is unchanged from what would be in a clean Rails app, just uncommented.
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.plural /^(ox)$/i, "\\1en"
inflect.singular /^(ox)en/i, "\\1"
inflect.irregular "person", "people"
inflect.uncountable %w( fish sheep )
end
Knowing exactly what methods are available on inflect
without looking at the stock comments requires us to look at the Rails API documentation. This is fine but is a context switch if we need to check documentation whenever we want to add to it.
By using a @param
tag, we can help Solargraph help us. If you CTRL (or CMD on a Mac) and click the inflections
call, Solargraph should take you to the definition of the method called. By doing this you can see that the class of the inflect
block arg is ActiveSupport::Inflector::Inflections
. Let’s add this to the snippet.
# @param inflect [ActiveSupport::Inflector::Inflections]
ActiveSupport::Inflector.inflections(:en) do |inflect|
inflect.plural /^(ox)$/i, "\\1en"
inflect.singular /^(ox)en/i, "\\1"
inflect.irregular "person", "people"
inflect.uncountable %w( fish sheep )
end
Now that we’ve done this, we should have code suggestions that match the API and the ability to view the documentation for them specifically without leaving our editor. This is a double-edged sword. You can tell Solargraph lies about the code this way, but its usefulness is great. Use with caution.
Summary
You should now have a much better editor experience with Rails in VSCode. This isn’t fully on par with RubyMine, but gives you more than enough assistance from within the editor rather than relying on Rails guides and the API documentation.
Solargraph can also help with verifying types of block args with the @param
tag, allowing you to have a better understanding of what methods are available to you from the yielded objects. Which, is incredibly useful for maintaining a Rails project long term and can help minimise the documentation comments Rails provides.