Automating Ruby Style Fixes with ProntoAutocorrect

As a Ruby developer, I’ve spent my fair share of time wrestling with code style tools like RuboCop and Pronto. They’re fantastic for keeping code clean, but let’s be honest—manually fixing linting errors across a codebase can feel like a slog. Worse, when bad style slips into your develop branch because CI only catches it post-merge, you’re stuck playing cleanup. I wanted a better way: a tool that automates style corrections with precision and safety, whether I’m linting a pull request’s changes or the whole project. So, I wrote (with the help of AI) ProntoAutocorrect.

Here’s the scoop on this Ruby script—what it does, how it works, and why it might save you (and your team) some headaches.

What Is ProntoAutocorrect?

ProntoAutocorrect is a command-line tool that combines Pronto’s diff-based linting with RuboCop’s auto-correction magic. It scans your Ruby files for style issues and fixes them in one go, offering both a “safe” mode for low-risk tweaks and an “aggressive” mode for deeper cleanups. You can run it against a base branch (like origin/develop) to catch changes in a PR, or sweep through all Ruby files in your current branch with the --all flag.

Here’s the script in action:

./pronto_autocorrect.rb origin/main -A

That’ll compare your current branch to origin/main and apply aggressive auto-corrections. Want to see it for yourself? Check out the full code at the end of this post.

Features

Here’s what it brings to the table:

  • Flexible Targeting: Compare against any branch (default: origin/develop) or lint all Ruby files—both Git-tracked and untracked—with --all, automatically ignoring files in .gitignore.
  • Safe vs. Aggressive Modes: Use -a (default) for safe fixes that won’t break logic, or -A for RuboCop’s full auto-correct power (watch out—semantics might shift!).
  • Batch Processing: Corrects files in chunks of 50 to avoid command-line length limits.
  • Real-Time Output: See Pronto’s linting and RuboCop’s fixes as they happen.
  • Smart Summaries: Get a rundown of files processed, time taken, and any lingering issues with next-step tips.

Run it with -h for the full usage guide:

./pronto_autocorrect.rb --help

Automate SSH logins when a password is required

Today I learned how to automate SSH logins when a password is required. In order to make this happen we need to first install expect

Install Expect

brew install expect

Create bash scripts

cd /usr/bin/local
touch exp
touch ssh-custom
chmod u+x exp ssh-custom

Open the exp file and enter in the following:

#!/usr/bin/expect -f
set timeout 20

set cmd [lrange $argv 0 end]

# Check if SSHPASS is set
if {[info exists env(SSHPASS)]} {
    set password $env(SSHPASS)
} else {
    puts "Error: SSHPASS environment variable not set."
    exit 1
}

spawn ssh $cmd
expect "password for your-username:"
send "$password\r"
interact

The string on the line expect "password for your-username:" will need to match the text that gets displayed when you ssh normally to whatever server is requiring a password. This will be what expect waits for before entering in your password.

Now open the ssh-custom file and enter the following. This will be what we eventually setup an alias for that will divert the ssh command to the exp file that will handle servers that require a password.

#!/bin/bash

if [ "$1" == "production" ]; then
    exp production
else
    # Default behavior for other SSH commands
    ssh "$@"
fi

Now we need to setup the environment variable and alias. Assuming you use zsh, add the following to your .zshrc file.

alias ssh="ssh-custom"
export SSHPASS="yoursshpassword"

Profit

Now when you run ssh production it will automatically enter your password.

How to bypass default_scope

Today I learned how to bypass default_scope using ActiveRecord::QueryMethods#unscope. And change a previously set where condition.

class Products
  default_scope where(enabled: true)
  scope :disabled, -> { unscope(enabled: false) }
end

Another helpful method is ActiveRecord::QueryMethods#rewhere

class Products
  default_scope where(enabled: true)
end

product = Products.first
product.rewhere(enabled: false)

Force string to boolean object

Problem

You have a report that expects a boolean. Sometimes the it is run from a job that passes in a boolean. And sometimes it is executed from a controller using a param that comes in as "true" or "false".

How do you ensure "true" and true are both treated as a boolean?

Solution

Force string to boolean using ActiveModel::Type::Boolean.new.cast

irb(main)> ActiveModel::Type::Boolean.new.cast('true')
=> true

irb(main)> ActiveModel::Type::Boolean.new.cast(true)
=> true

Force Rails Database Migration

Problem

Let’s say you create the following Rails migration forgetting to add code to the change method. You then issue the rails migration command rails migrate

class AddAwesomeToStuff< ActiveRecord::Migration[6.0]
  def change
  end
end

You then update the migration with your desired changes and try issuing the migrate command again. Nothing happens. It is because each time a migration runs the version number is stored in a table that prevents the same migration running more than once.

class AddAwesomeToStuff< ActiveRecord::Migration[6.0]
  def change
    change_table :stuff do |t|
      t.string :awesome
    end
  end
end

Solution

Force a migration to run in the Rails console

irb(main)> require "#{Rails.root.to_s}/db/migrate/20211004223636_add_awesome_to_stuff.rb"
irb(main)> AddAwesomeToStuff.migrate(:up)

Clean up RSpec Global Namespace

Today I learned (after reading this article) that in RSpec declared classes, modules, and structs are global. They pollute the global namespace and can cause order dependent spec failures. You can read up more on the topic here.

To avoid this you can this to your rails_helper.rb

RSpec.configure do |config|
  config.around(:example, remove_const: true) do |example|
    const_before = Object.constants

    example.run

    const_after = Object.constants
    (const_after - const_before).each do |const|
      Object.send(:remove_const, const)
    end
  end
end

Simplifying code using Rails presence Method

Rails has a useful method called presence that allows you to use the value of an object, otherwise it returns nil.

It is very simple. Below is the implemenation.

  def presence
    self if present?
  end

We can use it to refactor the following code

state   = params[:state]   if params[:state].present?
country = params[:country] if params[:country].present?
region  = state || country || 'US'

to this

region = params[:state].presence || params[:country].presence || 'US'