Let’s talk about keeping your Ruby code clean, fast, and secure. I’ve found that the best way to do this isn’t just by careful coding, but by using automated tools that act as a safety net. These tools look at your code while you write it, pointing out problems before they ever run. They save me from embarrassing bugs and help my team write consistently, even as a project grows.
I want to share seven specific tools, or “gems,” that I rely on. Each one has a different job, and together they cover almost everything I worry about. I’ll show you exactly how I use them, with code from my own projects.
First up is RuboCop. Think of it as a friendly but strict style guide. It makes sure everyone on a team writes code the same way. Things like indentation, naming, and the length of methods. Consistency might seem small, but it makes code much easier to read and maintain.
You control RuboCop with a .rubocop.yml file. You can turn rules on or off. When you’re starting, it’s okay to disable rules that feel too strict. You can adopt them later. You can also make your own rules for your specific project.
# This is my project's .rubocop.yml
Style/Documentation:
Enabled: false # I often skip forcing comments on every class
Metrics/MethodLength:
Max: 15 # Methods longer than 15 lines get a warning
Layout/LineLength:
Max: 120
AllowURI: true # It's okay if a long web link breaks the limit
# Here's a rule I wrote for our project
Custom/ServiceObjectName:
Description: 'Service classes should end with "Service"'
Enabled: true
Include:
- 'app/services/**/*.rb'
The best part is it can fix many issues automatically. I run bundle exec rubocop -a and it cleans up spacing, quotes, and other simple style problems. I also set it up to run before anyone can commit code, which keeps our main codebase tidy.
Next is a crucial tool for Rails apps: Brakeman. It checks for security holes. It looks for common mistakes that could let attackers in, like SQL injection or cross-site scripting. Running Brakeman feels like having a security expert review every line of your code for free.
You can configure it to ignore certain warnings or focus on specific areas. After you review a warning and decide it’s not a real threat, you can add it to an ignore file so it doesn’t clutter future reports.
# A simple custom check I added to look for a pattern we wanted to avoid
class CheckMissingAuthorization < Brakeman::BaseCheck
def run_check
# Look at all controller actions
tracker.controllers.each do |name, controller|
controller.methods.each do |method_name, method|
# If an action doesn't call our authorization method, warn us
unless method.contains_call?(:authorize_user)
warn :controller => name,
:action => method_name,
:warning_type => "Missing Authorization",
:message => "Controller action does not authorize user",
:confidence => :weak
end
end
end
end
end
I run Brakeman in our continuous integration pipeline. If it finds a new high-confidence security warning, the build fails. This stops vulnerable code from being deployed.
The third gem is Reek. While RuboCop looks at style, Reek looks at structure and design. It finds “code smells.” These aren’t bugs, but they are signs that your code might be confusing, too complex, or hard to change later.
Reek points out things like a class that has too many responsibilities, or a method that knows too much about another object’s internals. It helps you follow good design principles.
# My .reek.yml
detectors:
TooManyInstanceVariables:
max_instance_variables: 4 # Warn if a class has more than 4 @variables
FeatureEnvy:
enabled: true # Warns if a method uses another object's data more than its own
# I turn off some checks for test files
directories:
"spec/**/*":
IrresponsibleModule:
enabled: false
TooManyStatements:
enabled: false
Here’s a simplified example of code Reek would complain about. The class is trying to do too much.
class ReportGenerator
# TooManyInstanceVariables: This initializer sets up 5 different things.
def initialize(data, formatter, printer, email_client, logger)
@data = data
@formatter = formatter
@printer = printer
@email_client = email_client
@logger = logger
end
# TooManyStatements: This one method does many unrelated tasks.
def generate_and_distribute
formatted = @formatter.format(@data)
@printer.print(formatted)
@email_client.send(formatted)
@logger.log("Report sent")
save_to_database(formatted)
update_dashboard
end
end
Reek’s warning would push me to split this into smaller, focused classes.
Fourth is Fasterer. This gem is all about speed. Ruby is expressive, but sometimes that expressiveness comes with a performance cost. Fasterer knows the slower ways to write things and suggests faster alternatives.
It doesn’t guess about performance. It’s based on well-known patterns in Ruby. For example, using map instead of each with an empty array to collect results.
# Slower: Creates an array and repeatedly appends to it.
results = []
items.each do |item|
results << item.calculate
end
# Faster: `map` is designed for this transformation.
results = items.map(&:calculate)
# Slower: Two separate checks over the array.
if allowed_names.include?(user.first_name) || allowed_names.include?(user.last_name)
grant_access
end
# Faster: One check using a set intersection.
if ([user.first_name, user.last_name] & allowed_names).any?
grant_access
end
These changes are small and often make the code clearer as well as faster. I run Fasterer occasionally, especially when working on performance-critical sections of the application.
The fifth tool addresses a critical external risk: vulnerable libraries. It’s called bundler-audit. It scans your Gemfile.lock and checks every gem version against a database of known security vulnerabilities.
A secure application with a vulnerable library is not secure. This tool ensures you know about problems in your dependencies.
I set it up as a Rake task and make it run automatically in our deployment process.
# In my Rakefile
require 'bundler/audit/task'
Bundler::Audit::Task.new
# A custom task to update the database and check
task :audit do
puts "Updating vulnerability database..."
`bundle audit update`
puts "Checking for vulnerable gems..."
`bundle audit check`
end
Sometimes a vulnerability doesn’t apply to your specific use case. You can document that decision in an ignore file.
# .bundler-audit.yml
ignore:
- CVE-2020-11076
gem: rack
reason: "We do not use the vulnerable multipart parsing feature."
This creates a record for your team, so everyone knows why a particular warning was accepted.
Sixth is StandardRB. This is an opinionated tool. It takes all the debates about code style—single vs. double quotes, where to put spaces—and makes a decision for you. The philosophy is, “It doesn’t matter what the rule is, just that everyone follows the same one.”
The configuration is minimal, which is the point. You spend less time arguing about style and more time writing features.
# .standard.yml - that's it. This is often the whole file.
# Maybe one or two tweaks:
fix: true # Auto-fix what you can on report
parallel: true # Use multiple CPUs to run faster
format: progress # Simple output format
I integrate it directly into my editor. As I type, it underlines style violations and can fix them with a keystroke. This makes following the standard effortless.
The seventh and final gem isn’t a single tool, but the practice of putting them all together. The real power comes from automation. I don’t run these commands by hand every time. They run automatically.
I set up a pre-commit hook with Git. This script runs the linters before a commit is finalized. If the code is messy, the commit stops.
#!/bin/bash
# .git/hooks/pre-commit
echo "=== Running Code Quality Checks ==="
# Stop if RuboCop finds style violations
bundle exec rubocop --force-exclusion || exit 1
# Stop if StandardRB finds issues
bundle exec standardrb || exit 1
echo "✓ All checks passed."
More importantly, everything runs in our continuous integration (CI) service, like GitHub Actions or GitLab CI. Every pull request triggers a full suite of checks.
# A simplified GitHub Actions workflow (.github/workflows/ci.yml)
name: CI
on: [push, pull_request]
jobs:
quality:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ruby/setup-ruby@v1
- run: bundle install
- run: bundle exec rubocop
- run: bundle exec standardrb
- run: bundle exec brakeman -q -z
- run: bundle exec bundle audit check --update
If any of these steps fail, the PR gets a red X. It can’t be merged until the problems are fixed. This makes code quality a non-negotiable part of our process.
To wrap up, using these tools changed how I write Ruby. They catch my mistakes, teach me better patterns, and protect the project from common pitfalls. They work for me while I sleep, checking every new line of code that gets added.
Start with one. Maybe RuboCop or StandardRB to clean up style. Then add Brakeman for security. Let them run automatically. You’ll quickly wonder how you ever managed a codebase without them. Your code will be more consistent, more secure, and easier for everyone on your team to understand and improve.