LinkedIn carousel for the tsrange, testable scopes, and CurrentAttributes post.
Slide 1 — Hook — 1080 × 1080
The design choice that changes testing
Accept a now parameter.
Slide 2 — The Usual Way — 1080 × 1080
Time.current hardcoded, travel_to everywhere
The usual way
scope :active, -> {
where("tsrange(...) @> ?",
Time.current)
}
It works, but the time manipulation is infrastructure, not intent. The tests read like plumbing.
Slide 3 — The Fix — 1080 × 1080
Accept a now parameter, tests read like specs
The fix
scope :active, lambda { |now = Time.current|
where("tsrange(...) @> ?::timestamp",
now)
}
# No travel_to, no frozen clocks
now = Time.zone.parse("2026-07-23 12:00")
expect(Banner.active(now))
.to contain_exactly(permanent, temporary)
Slide 4 — Safety Net — 1080 × 1080
Verify SQL and Ruby always agree
The safety net
active_banners = Banner.active(now)
expect(active_banners
.map { |b| b.active?(now) })
.to be_all(true)
If someone changes the boundary semantics in one but forgets the other, this test catches it.
Slide 5 — Takeaway — 1080 × 1080
Full post CTA
The full post covers the tsrange pattern, an Activatable concern, and a CurrentAttributes approach where you set the time once per request and every scope uses it automatically.
Read the full post at dcyoung.dev