activerecord

“Write Amplification” Guard: Only Update Changed Columns

Avoid writing rows when nothing changed—especially in batch jobs. Check changed? or compute the would-be update and skip if identical. This reduces bloat and autovacuum pressure.

Database migrations and schema management

Rails migrations evolve database schema over time. I use change method for reversible migrations. Migrations create tables, add/remove columns, add indices. up and down methods provide explicit control. Irreversible migrations like data transformation

Optimistic Locking for Collaborative Edits

If multiple admins edit the same record, use lock_version. Rails will raise on conflicting updates, and you can show a friendly “this changed underneath you” message. It prevents subtle lost updates.

ActiveRecord callbacks for lifecycle hooks

Callbacks hook into the ActiveRecord lifecycle to execute code before or after operations like create, update, or destroy. I use before_validation to normalize data (like downcasing emails), after_create to trigger welcome emails, and before_destroy t

Safer “find or create” with Unique Constraint + Retry

Race conditions happen. The correct “find or create” in production uses a unique constraint and a retry on conflict, not a naive check-then-insert. Let the database serialize the race.

Fast “Exists” Checks with select(1) and LIMIT

Avoid loading whole records when you only need to know if something exists. exists? is good; for complex joins, a scoped select(1).limit(1) can be clearer and keeps the DB workload low.

Bulk Upsert with insert_all + Unique Index

I stopped doing row-by-row imports once they started hammering the DB. In Migration (unique index), I added a real uniqueness guarantee on provider + uid, because bulk writes only stay correct if the database can enforce constraints. Then, in Bulk ups

Deterministic Sorting with Secondary Key

If you sort by a non-unique column (score, created_at), pagination can “skip” or “duplicate” records. Always add a secondary unique key like id for deterministic ordering.

Use `touch_all` for Efficient “Bump Updated At”

When you need to invalidate caches by changing timestamps, use touch_all to avoid per-record callbacks. It’s fast, explicit, and doesn’t run unintended side effects.

Safe Pagination with Keyset (No OFFSET)

OFFSET gets slower as tables grow and becomes inconsistent under writes. Keyset pagination is stable and fast: paginate by (created_at, id) cursor. This is a common “senior Rails” upgrade for activity feeds.

Avoid Memory Blowups: find_each + select Columns

Backfills often fail because we accidentally load full records and associations. Use select to fetch only needed columns and find_each to keep memory flat. This is basic, but it’s where outages come from.

Prevent Long Transactions with after_save_commit for Heavy Work

Heavy work inside a transaction increases lock time and deadlock risk. Use after_save_commit to schedule slow tasks (thumb generation, external sync) once the write is durable.