Errors as you type, in Rails' own words

Ruby is parsed with Prism for your app's Ruby version, HTML as browsers read it, and every render is looked up the way Rails would. These are the server's messages for this view.

app/views/users/index.html.erb
<% @users.each do |user| %>
  <%= render "users/card", user: user %>
<% end %>

<div class="banner">
  <img src="/banner.png">
  <%= render "users/car" %>
</span>
  1. <img> without alt: the alt attribute must be specified (HTML 4.8.4.4.1)6:3img-missing-alt
  2. Missing partial users/_car7:15unresolved-render
  3. End tag </span> doesn't close the open <div> (line 5) (HTML 13.2.6.4.7)8:1mismatched-close-tag

Every diagnostic, with how to turn it off

It knows your app

Hover, go to definition and completion follow Rails conventions from the template you are editing.

Where the cursor is, and what you get
In the templateYou get
render "users/card"Go to the partial, hover shows the file, completion of partial names, find all renders
@userCompletion, hover and go to definition from the action and its before_actions
users_pathCompletion, hover with the URL and controller#action, go to config/routes.rb
t(".title")Completion, hover with each locale's value, go to the locale file
report.titleColumn type, null: and default: on hover, go to db/schema.rb
data-controller="search"Stimulus controller names, actions, targets and values

Navigation and completion in detail

One partial, three languages

The same checks, lookups and formatter in ERB, Haml and Slim, highlighted here by the extension's own grammars.

users/_badge.html.erb
<%# locals: (user:) %>
<article class="badge" id="<%= dom_id(user) %>">
  <h2><%= link_to user.name, user_path(user) %></h2>
  <% if user.admin? %>
    <p class="badge__role"><%= t(".admin") %></p>
  <% end %>
</article>
users/_badge.html.haml
-# locals: (user:)
%article.badge{id: dom_id(user)}
  %h2= link_to user.name, user_path(user)
  - if user.admin?
    %p.badge__role= t(".admin")
users/_badge.html.slim
/# locals: (user:)
article.badge id=dom_id(user)
  h2 = link_to user.name, user_path(user)
  - if user.admin?
    p.badge__role = t(".admin")

More examples

Formatting that only moves whitespace

Indentation, trailing spaces and the final newline, nothing else: lines are never wrapped or joined and Ruby is never touched. If the result would not compile to the same template, the file is left alone.

Before
<% if @user.admin? %>
<nav class="admin">
      <%= link_to "Users", admin_users_path %>
  <% @reports.each do |report| %>
<p><%= report.title %></p>
    <% end %>
</nav>
<% end %>
After Format Document
<% if @user.admin? %>
  <nav class="admin">
    <%= link_to "Users", admin_users_path %>
    <% @reports.each do |report| %>
      <p><%= report.title %></p>
    <% end %>
  </nav>
<% end %>

How the formatter decides

The same checks in CI

The language server's checks and formatter also ship as a command line on npm, so the editor and the pipeline agree. Exit codes: 0 ok, 1 diagnostics or files that would change, 2 usage or I/O errors.

Terminal
npm install --save-dev @x-ror/ruby-templates
npx ruby-templates check app/views            # errors and warnings; exit 1 if any
npx ruby-templates format --check app/views   # files that would change; exit 1 if any
npx ruby-templates format --write app/views   # format them

Command line options