class DailySignupRollup < ApplicationRecord
validates :day, presence: true, uniqueness: true
validates :total, :verified, numericality: { greater_than_or_equal_to: 0 }
scope :for_range, ->(from, to) do
where(day: from.to_date..to.to_date).order(:day)
end
scope :recent, ->(days = 30) do
for_range(days.days.ago, Time.zone.today)
end
def signup_rate
return 0.0 if total.zero?
(verified.to_f / total).round(4)
end
end
class RollupSignupsJob < ApplicationJob
queue_as :low
def perform(date = Time.zone.yesterday)
day_start = date.to_date.beginning_of_day
day_end = day_start + 1.day
scope = User.created_between(day_start, day_end)
total = scope.count
verified = scope.verified.count
DailySignupRollup.upsert_all(
[{
day: day_start.to_date,
total: total,
verified: verified,
created_at: Time.current,
updated_at: Time.current
}],
unique_by: :day
)
end
end
class User < ApplicationRecord
# half-open interval [start, finish) avoids double-counting the boundary row
scope :created_between, ->(start, finish) do
where("created_at >= ? AND created_at < ?", start, finish)
end
scope :verified, -> { where.not(confirmed_at: nil) }
scope :signed_up_on, ->(date) do
day = date.to_date.beginning_of_day
created_between(day, day + 1.day)
end
end
This snippet shows a common analytics pattern in Rails: pre-aggregating raw event rows into a compact daily rollup table so dashboards read a handful of summary rows instead of scanning millions of users. The rollup is recomputed on a schedule and made idempotent so re-running a day never double-counts.
In DailySignupRollup model, each row represents one calendar day, keyed by a unique day column. The dedupe_key uniqueness (here just day) means a rerun overwrites rather than inserts. The for_range scope filters rollups for reporting, and the signup_rate helper derives a value from stored columns so the read side stays trivial. Storing both total and verified keeps the table useful without recomputing from raw data.
The RollupSignupsJob job does the actual aggregation. It groups User records created within a UTC day boundary using group_by_day semantics expressed as a plain GROUP BY on a truncated timestamp, counting total and verified signups per day. The key detail is upsert_all with unique_by: :day: Postgres performs an INSERT ... ON CONFLICT (day) DO UPDATE, so the job is safe to re-run for backfills or after a crash. It accepts a date argument, defaulting to yesterday, which lets the scheduler process the just-completed day while a human can replay any historical date. Working in Time.zone and normalizing to beginning_of_day avoids off-by-one bucketing across time zones — a classic rollup pitfall.
The User signups scope tab holds the query building blocks the job leans on: created_between bounds the window with a half-open interval [start, end) to avoid double-counting midnight rows, and verified filters confirmed accounts. Keeping these as scopes means the job reads declaratively and the same predicates can be reused in tests or ad-hoc reports.
The trade-off is freshness: rollups lag by the scheduling interval, so they suit reporting, not real-time counters. When a day's raw data changes late (backfilled signups), the date-argument design plus the upsert make correction a one-line replay. A developer reaches for this when dashboard queries grow expensive and eventual consistency on aggregates is acceptable.
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.