class RevenueStat
DEFAULT_RANGE = 30.days
def initialize(account, range: DEFAULT_RANGE)
@account = account
@range = range
end
def mrr_cents
@mrr_cents ||= Rails.cache.fetch(cache_key, expires_in: 5.minutes) do
compute_mrr_cents
end
end
def growth_ratio
previous = previous_period_mrr_cents
return nil if previous.zero?
((mrr_cents - previous).to_f / previous).round(4)
end
def cache_key
["revenue_stat", @account.id, window.begin.to_i, window.end.to_i].join("/")
end
private
def window
@window ||= @range.ago..Time.current
end
def compute_mrr_cents
@account.subscriptions
.active
.where(started_at: window)
.sum(:monthly_amount_cents)
end
def previous_period_mrr_cents
@previous_period_mrr_cents ||= @account.subscriptions
.active
.where(started_at: (window.begin - @range)..window.begin)
.sum(:monthly_amount_cents)
end
end
class DashboardsController < ApplicationController
before_action :authenticate_user!
def index
account = current_user.account
@revenue = RevenueStat.new(account)
@signups = SignupStat.new(account, range: 7.days)
respond_to do |format|
format.html
format.json do
render json: {
mrr_cents: @revenue.mrr_cents,
growth_ratio: @revenue.growth_ratio,
signups: @signups.count
}
end
end
end
end
<section class="dashboard-stats">
<article class="stat stat--revenue">
<h2>Monthly Recurring Revenue</h2>
<p class="stat__value">
<%= number_to_currency(@revenue.mrr_cents / 100.0) %>
</p>
<% if (ratio = @revenue.growth_ratio).present? %>
<p class="stat__trend <%= ratio >= 0 ? 'is-up' : 'is-down' %>">
<%= number_to_percentage(ratio * 100, precision: 1) %>
<span>vs previous period</span>
</p>
<% else %>
<p class="stat__trend is-neutral">No prior data</p>
<% end %>
</article>
<article class="stat stat--signups">
<h2>New Signups (7d)</h2>
<p class="stat__value"><%= @signups.count %></p>
</article>
</section>
This snippet shows a common Rails pattern for keeping dashboards fast and controllers thin: a dedicated query object that owns one expensive aggregate, memoizes it per instance, and layers a short-lived cache on top so the same numbers are not recomputed on every request.
In RevenueStat, the class is initialized with an account and an optional time range, so the same object can answer questions about any window. The core work lives in mrr_cents, which uses Rails.cache.fetch keyed on the account and range to avoid hitting Postgres repeatedly, and delegates the actual SQL to the private compute_mrr_cents. That method uses a single grouped sum over active subscriptions so the aggregation happens in the database rather than by loading rows into Ruby. The ||= on @mrr_cents provides in-process memoization, which matters when several parts of a request touch the same stat within one object's lifetime.
The cache_key method builds a stable, human-readable key from the account id and the range boundaries, and growth_ratio shows how a second derived figure can be composed from the memoized base without re-querying. The guard against a zero previous period avoids a divide-by-zero and returns nil so the view can decide how to render a missing trend.
In DashboardsController, the action stays declarative: it instantiates one RevenueStat and one SignupStat, exposing them as @revenue and @signups. Because the query objects memoize internally, the controller and view can call the same reader multiple times cheaply. Using helper_method-free plain instance variables keeps the flow obvious.
The view tab dashboard/index.html.erb renders the computed values, formatting cents with number_to_currency and treating a nil growth_ratio as a neutral state. This separation matters because it puts all query knowledge in one testable object, keeps caching concerns out of the controller, and makes it trivial to unit test compute_mrr_cents in isolation. The main trade-off is cache staleness: expires_in trades perfect freshness for fewer queries, which is usually the right call for a dashboard where second-level accuracy is unnecessary. Reaching for this pattern makes sense whenever a stat is expensive, reused, and read far more often than it changes.
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
package dbutil
import (
"context"
"github.com/jackc/pgconn"
Retry Postgres serialization failures with bounded attempts
require "csv"
class PeopleCsvStream
include Enumerable
HEADERS = %w[id full_name email signed_up_at plan].freeze
Resilient CSV Export as a Streamed Response
Share this code
Here's the card — post it anywhere.