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