Redis caching for expensive computations

Redis provides a fast, in-memory cache for expensive computations that don't change frequently. I use Rails.cache with the Redis store to cache things like trending posts calculations, aggregated statistics, or external API responses. The fetch method

Database constraints for data integrity

While ActiveRecord validations catch most invalid data, database constraints provide a safety net that prevents invariant violations even when validations are bypassed. I add null: false constraints for required columns, unique indexes for uniqueness

Polymorphic associations for flexible relationships

Polymorphic associations allow a model to belong to multiple other models through a single association, which is useful for shared behaviors like comments, likes, or attachments. Instead of separate post_id and article_id columns, a polymorphic associ

Background job retry strategies

Not all background job failures should be retried the same way. Transient failures like network timeouts benefit from exponential backoff, but bugs in code or invalid data should fail immediately after a few attempts. Sidekiq provides retry configurat

Webhook signature verification

When receiving webhooks from external services, signature verification ensures the payload comes from the claimed sender and hasn't been tampered with. Services like Stripe and GitHub include an HMAC signature in headers computed from the request body

N+1 prevention with includes and preload

Eager loading associations with includes, preload, or eager_load is essential for avoiding N+1 queries that kill performance. When rendering a list of posts with their authors, Post.includes(:author) loads all authors in a second query rather than fir

Model validations for data integrity

Validations ensure data consistency before persisting to the database, catching invalid states early in the request lifecycle. I combine presence validations for required fields, uniqueness constraints that map to database indexes, and format validati

Database connection pooling configuration

Properly configured connection pools prevent ActiveRecord::ConnectionTimeoutError during traffic spikes while avoiding resource waste. The pool size should match your application's concurrency needs—for Puma with 5 threads per worker, I set pool: 5 in

API request logging for debugging and analytics

Comprehensive request logging provides visibility into API usage patterns, performance bottlenecks, and security incidents. I log structured JSON that includes request method, path, parameters (sanitized to exclude passwords), response status, duratio

Counter cache for association counts

Computing counts on associations can be expensive when done repeatedly—post.comments.count executes a SELECT COUNT(*) query every time. Counter caches solve this by maintaining a denormalized count column on the parent model that increments/decrements

Optimistic locking for concurrent updates

When multiple users can update the same record simultaneously, optimistic locking prevents lost updates by detecting conflicts. Rails provides built-in support via a lock_version integer column that increments on every update. If two users load the sa

Serializers with ActiveModel::Serializers

Controllers shouldn't know about JSON structure—that's a serialization concern. ActiveModel::Serializers (AMS) separates presentation from business logic by defining dedicated serializer classes for each model. Serializers specify exactly which attrib