Safer HTML Sanitization Pipeline

User content needs defense in depth: markdown rendering + sanitization + link attribute hygiene. Keep the allowed tags list explicit and test it. Don’t trust upstream renderers to be safe by default.

Database-Backed “Run Once” Migrations for Maintenance Tasks

Sometimes you need a one-time maintenance operation outside normal schema changes. Use a small table to track “run once” tasks so reruns are safe and the operation is visible.

ActiveRecord Encryption for PII Fields

Rails’ built-in encryption makes it easier to protect PII at rest. Use it for fields like phone numbers or external tokens. Combine with deterministic encryption when you need lookup-by-value.

Validated JSON Schema with dry-validation-style contract (lightweight)

Even without extra gems, you can validate incoming JSON payloads with small “contracts” that coerce and validate keys. It’s a strong reliability upgrade for webhook and API ingestion.

Guard Rails for Dangerous Admin Actions

Admin actions are production sharp edges. Require a typed confirmation string, log actor + request_id, and run the dangerous work in a background job. This reduces accidental incidents.

Time Zone Safe Scheduling

Scheduling bugs are often time zone bugs. Persist times in UTC, accept user input in their zone, and convert explicitly. Keep conversions close to the boundary (forms/controllers).

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.