class Post < ApplicationRecord
# View counter - increments without hitting the database
kredis_counter :view_count, expires_in: 1.day
# Recent viewers list - stores last 10 viewer IDs
kredis_unique_list :recent_viewers, limit: 10
# Flag for featured status
kredis_flag :featured
# Hash for cached statistics
kredis_hash :statistics
def increment_views!(user_id)
view_count.increment
recent_viewers.prepend(user_id)
# Update database counter periodically
if view_count.value % 10 == 0
update_column(:views, views + 10)
end
end
def viewer_count
recent_viewers.elements.size
end
def stats
statistics.entries.presence || compute_and_cache_stats
end
private
def compute_and_cache_stats
stats = {
'likes' => likes.count,
'comments' => comments.count,
'shares' => shares.count
}
statistics.update(stats)
stats
end
end
module Api
module V1
class PostsController < ApplicationController
def show
post = Post.find(params[:id])
# Increment view count
post.increment_views!(current_user&.id || "anon_#{request.remote_ip}")
render json: post.as_json.merge(
view_count: post.view_count.value,
viewer_count: post.viewer_count,
statistics: post.stats
)
end
end
end
end
Kredis provides typed Redis structures as Active Model attributes, simplifying common patterns like counters, flags, and lists. Instead of raw Redis commands, I define kredis accessors on models that handle serialization automatically. Counters track metrics like view counts, lists manage ordered collections, and flags store boolean states. Kredis uses connection pooling and handles expiration seamlessly. For real-time features, I combine Kredis with Action Cable—store online users in a Redis set, broadcast presence updates. The library integrates with Rails' encrypted credentials for sensitive data. This abstraction makes Redis feel like native Rails, improving developer productivity while maintaining performance.
Related snips
class CommentsController < ApplicationController
before_action :set_post
def create
@comment = @post.comments.build(comment_params)
System test: asserting Turbo Stream responses
class Post < ApplicationRecord
belongs_to :author, class_name: 'User'
has_many :comments, dependent: :destroy
scope :published, -> { where.not(published_at: nil).where('published_at <= ?', Time.current) }
scope :draft, -> { where(published_at: nil) }
ActiveRecord scopes for reusable query logic
module Api
module V1
class UsersController < BaseController
def show
user = User.includes(:profile).find(params[:id])
ETags for conditional requests and caching
class PostsController < ApplicationController
def index
@posts = Post.includes(:author)
.order(created_at: :desc)
.page(params[:page])
.per(10)
Turbo Frames: infinite scroll with lazy-loading frame
require "csv"
class PeopleCsvStream
include Enumerable
HEADERS = %w[id full_name email signed_up_at plan].freeze
Resilient CSV Export as a Streamed Response
<form data-controller="query-sync" data-action="change->query-sync#apply">
<select name="status" class="rounded border p-2">
<option value="">Any</option>
<option value="open">Open</option>
<option value="closed">Closed</option>
</select>
Filter UI that syncs query params via Stimulus (no front-end router)
Share this code
Here's the card — post it anywhere.