Style Guide

January 27, 2026 · View on GitHub

Block Delimeters for multi-line chaining

Prefer {...} over do...end for multi-line chained blocks.

We use the enforced style braces_for_chaining.

For example:

BAD:

array_of_things.each do |thing|
  thing if thing.condition?
end.compact

GOOD:

array_of_things.each { |thing|
  thing if thing.condition?
}.compact

Timeout.timeout needs custom exception

If we use Timeout.timeout without a custom exception, rescue blocks may be prevented from executing.

For example:

BAD:

Timeout.timeout(run_timeout)

GOOD:

Timeout.timeout(run_timeout, SomeModule::SomeError)

Rails/OutputSafety

We explictly enabled the Rails/OutputSafety cop to ensure its usage. It prevents usage of raw, html_safe, or safe_concat unless they are explicitly disabled.

This blog post explains our feelings on unsafe HTML rendering.

Use parentheses for percent literal delimeters

We enforce usage of parentheses for all percent literal delimeters besides %r (the macro for regexps) for which we use curly braces.

GOOD:

%w(one two three)
%i(one two three)
%r{(\w+)-(\d+)}

BAD:

%w[one two three]
%i[one two three]
%w!one two three!
%r((\w+)-(\d+))

Naming/VariableNumber

We enforce the style "snake_case", which means that we prefer to name variables that end in a number with an extra underscore.

GOOD:

user_1 = User.first
user_2 = User.second

BAD:

user1 = User.first
user2 = User.second

The snake case style is more readable.

Betterment/ServerErrorAssertion

In RSpec tests, we prevent HTTP response status assertions against server error codes (e.g., 500). While it’s acceptable to “under-build” APIs under assumption of controlled and well-behaving clients, these exceptions should be treated as undefined behavior and thus do not need request spec coverage. In cases where the server must communicate an expected failure to the client, an appropriate semantic status code must be used (e.g., 403, 422, etc.).

GOOD:

expect(response).to have_http_status :forbidden
expect(response).to have_http_status 422

BAD:

expect(response).to have_http_status :internal_server_error
expect(response).to have_http_status 500

Betterment/NonNamespacedClass

This cop prevents defining classes at the top level without a namespace. All classes should be defined within a module namespace to avoid polluting the global namespace and to better organize code.

BAD:

class MyClass
  def my_method
  end
end

GOOD:

module MyNamespace
  class MyClass
    def my_method
    end
  end
end

or using the :: syntax:

class MyNamespace::MyClass
  def my_method
  end
end

Betterment/SimpleDelegator

This cop requires you to use Rail's delegate class method instead of SimpleDelegator in order to explicitly specify the set of delegating methods.

BAD:

class GearPresenter < SimpleDelegator
  def ratio_string
    ratio.to_s
  end
end

GOOD:

class GearDelegator
  attr_reader :gear

  delegate :ratio, to: :gear

  def initialize(gear)
    @gear = gear
  end

  def ratio_string
    ratio.to_s
  end
end