Hot Path Memoization (within request only)

Memoization is useful, but it should be scoped. Memoize within the instance/request, never globally. This is a simple way to avoid repeated expensive DB reads inside a view render.

Safer Background Job Arguments (Serialize IDs only)

Jobs should accept simple primitives (IDs, strings), not full objects. It avoids serialization surprises and makes jobs resilient across deploys. This also reduces job payload size.

Graceful Degradation: Feature-Based Rescue

Not every failure should be a 500. If a non-critical dependency fails (e.g., recommendations), rescue narrowly, emit a metric/log, and serve a baseline response.

Database Views for Read Models

Some read paths want a denormalized shape without materializing a new table. Postgres views are a clean option. Keep the view definition in a migration and map it with a read-only model.

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.

Granular Cache Invalidation with touch: true

When a child record changes, you often want the parent cache key to change too. touch: true is a clean primitive for that. It keeps fragment caching sane without complex dependency graphs.

Content Security Policy (CSP) Starter

CSP is a strong defense-in-depth measure for XSS. Start with report-only to learn what breaks, then enforce. Keep it explicit and include nonces for inline scripts when needed.

Keep DB Connections Healthy in Long Jobs

Long-running jobs can hit stale connections. Wrap work in with_connection and consider verify! before heavy DB usage. This reduces “PG::ConnectionBad” noise during long maintenance tasks.

Database-Backed Unique Slugs with Retry

Slug generation is deceptively racy under concurrency. Use a unique index plus retry with a suffix. Keep it deterministic and fast; don’t query in a loop without bounds.

Service-Level “Circuit Breaker” (Simple)

When a dependency is failing, you don’t want to keep hammering it. A simple circuit breaker trips after N failures and short-circuits for a cooldown window. It protects your app and your vendor.

Deterministic Cache Keys for Collections

When caching lists, include inputs that change the list (filters, page, member permissions). A deterministic cache key function prevents subtle “wrong user saw wrong list” bugs.

Sensitive Param Filtering for Logs

If you ever need to hand logs to support, you don’t want secrets in them. Filter params at the framework level; then add custom filters for app-specific fields (API keys, tokens).