Ruby Style Guide
by Convext
Ruby language style guide
Rules (33)
Config
Config in env vars, not code. Never commit .env. Commit .env.example. Never hardcode secrets.
Database
Passwords: bcrypt. API keys: encrypt. PII: field-level encryption. Never log sensitive data.
Dependencies
Use latest stable versions. Fix breaking changes—don't avoid upgrades. Check official registries.
Formatting
StandardRB: no config, no debates. RuboCop with opinionated defaults. Just run `standardrb --fix`.
Git
Small, focused commits. Use: feat/fix/refactor/test/docs/chore. Each commit independently deployable.
Linting
RuboCop with .rubocop.yml config. Inherit from rubocop-rails, rubocop-minitest. Auto-correct safe cops.
Llm Behavior
User and tests define done. Don't redefine scope or declare partial progress as complete.
No excuses: 'pre-existing', 'unrelated', 'tedious', 'for now'. Recognize and continue working.
You wrote every line. No 'pre-existing issues'—only issues you haven't fixed yet.
Package Manager
Gemfile + Gemfile.lock. `bundle install --deployment` in prod. Groups for dev/test. `bundle exec` for commands.
Rails
Rails.application.credentials for secrets. `rails credentials:edit`. Environment-specific credentials. Never commit master.key.
Sidekiq for heavy background work. Redis required. Use perform_later. Retries with exponential backoff.
Pundit policies for authorization. `authorize @record` in controllers. Policy classes match models.
Ruby
Favor modules and dependency injection over deep inheritance. Max 2-3 inheritance levels. Duck typing over type checking.
Add `# frozen_string_literal: true` to files. Prevents mutation bugs, improves performance.
Return meaningful values or `self`. Predicates (`?`) return booleans. Bang methods (`!`) mutate or raise.
Use pattern matching, endless methods (`def x = ...`), hash shorthand `{x:}`, numbered params `_1`. Ruby 3.2+.
Sinatra for microservices and simple APIs. Modular style for larger apps. Rack middleware compatible.
Hanami for DDD-style Ruby apps. Explicit dependencies. Actions over controllers. Repositories for persistence.
Security
Allowlists, not denylists. Validate type/length/format. Sanitize HTML. Parameterized queries only.
Auth: bcrypt/argon2 for passwords, rate limiting, secure sessions/tokens. Authz: check permissions on every request, use policy objects or middleware.
Force SSL, redirect HTTP→HTTPS, secure cookies (Secure/HttpOnly/SameSite), HSTS headers.
Testing
Test real instances. Mocking the class under test hides bugs.
Fix failures immediately. No skipping, no "pre-existing issues." Own the codebase state—a test suite with ignored tests can't be trusted.
Mock only: external HTTP APIs, time, filesystem side effects, third-party services. Use real implementations for internal services, database, and business logic.
Test public interfaces, inputs/outputs. Tests must survive refactoring. Don't test private methods.
1) Write failing test 2) Minimum code to pass 3) Refactor. Every line has a reason.
One logical concept per test. Multiple asserts OK if same concept. Clear test names describing behavior.
RSpec describe/context/it. let/let! for setup. FactoryBot for data. Avoid excessive mocking.
Capybara for system tests. Use semantic selectors. Wait for async. Headless Chrome in CI.
Use consistent test data setup: fixtures for stable reference data, factories for dynamic scenarios. Avoid inline object creation scattered throughout tests.
Workflow
Verify changes locally: run app, run tests, check for errors. CI catches environment issues, not basic bugs.
Format → Lint → Test before every commit. Never rely on CI for basic checks.
Language Standards (1)
Use this Ruleset
Sign in to adopt or fork this ruleset
Sign in with GitHubStatistics
- Rules
- 33
- Standards
- 1
- Projects using
- 0
- Created
- Jan 15, 2026