A Ruby Language Server

Solargraph and Rails

Ruby on Rails uses a lot of “magic” that makes it difficult, but not impossible, to gather code intelligence through static analysis. This page explains the current progress and provides some tips for improving Solargraph’s intellisense features in Rails projects.

Quick Start

There are two simple steps that should partially improve intellisense with Rails:

  1. Run solargraph bundle from your Rails project’s root directory.
  2. Add the most recent version of this file to the project:

Documenting Gems with solargraph bundle

The gems at the core of Rails (actionpack, activerecord, etc.) contain little to no YARD documentation. They generally use RDoc syntax instead. In order to make the most use of the existing documentation, solargraph bundle creates a special documentation cache that gets generated from RDoc and converted to YARD. Solargraph has a whitelist of Rails-related gems that require this alternative. Any other gems receive the usual YARD documentation.

The Comment File

The code in the gist should be added as a Ruby file somewhere that makes it visible to Solargraph, e.g., a file named definitions.rb in the config directory. Since the file only contains comments, Solargraph will process it but it has no impact on the runtime. The comments contain YARD directives that fill some of the gaps in Solargraph’s understanding of the Rails app.

This section, for example, exposes some of the ActiveRecord methods that are defined at runtime but are not discoverable through static analysis:

# @!parse
#   class ActiveRecord::Base
#     extend ActiveRecord::QueryMethods
#     extend ActiveRecord::FinderMethods
#     extend ActiveRecord::Associations::ClassMethods
#     include ActiveRecord::Persistence
#   end

The custom @!override directive allows you to inject your own YARD tags into external methods. This example applies overloads to ActiveRecord::FinderMethods#find so your models can infer the correct types from your models’ find methods:

# @!override ActiveRecord::FinderMethods#find
#   @overload find(id)
#     @param id [Integer]
#     @return [self]
#   @overload find(list)
#     @param list [Array]
#     @return [Array<self>]
#   @overload find(*args)
#     @return [Array<self>]
#   @return [self, Array<self>]

Rails support is very much a work in progress. If you have any questions or comments, please post them to the gist or the related GitHub issue.