
February 13, 2026
Range on Rails: How PostgreSQL Multirange Turned Complex Booking Logic into Elegant Simplicity

At Kaigi on Rails 2025, Tomohiro Umeda from RIZAP Technologies presented a real-world backend engineering case study: how to build a flexible reservation system — without fixed time slots — using PostgreSQL’s Range and Multirange types.
The talk, titled:
“Range on Rails — How Multirange Dramatically Simplified Complex Logic”
demonstrates how reframing a problem mathematically can replace tangled conditional logic with clear, declarative data operations.
https://rubygems.org/gems/ruby-libgd
The Problem: Reservations Without Fixed Slots
Traditional booking systems rely on predefined time blocks:
- 12:00–13:00
- 13:00–14:00
- 14:00–15:00
Users pick one.
However, chocoZAP, a 24-hour unmanned gym service, needed something fundamentally different:
👉 Users should be able to reserve any arbitrary interval, such as:
- 12:10–12:45
- 18:07–18:32
- 02:15–03:00
No rigid slots. No artificial boundaries.
According to the presentation, the goal was to enable users to “freely reserve their preferred time” without being constrained by predefined frames. 最新_登壇資料詳細_Kaigi_on_Rails_2025_梅…
Why This Is Hard
Without fixed slots, availability checks become significantly more complex.
Each booking request must account for overlapping constraints:
- Existing reservations
- Facility closures
- Maintenance windows
- Operational limits
- Partial overlaps
The problem is no longer discrete — it becomes continuous.
SPONSOR – JOB BOARD
SPONSOR – JOB BOARD
The Key Insight: Model Everything as Time Ranges
Instead of adding more conditionals, the team reframed the problem.
👉 Treat every constraint as a time interval.
- Unavailable periods → a set of ranges
- Requested period → another range
- Availability → set difference
The presentation describes this approach as viewing non-reservable periods as a “collection of ranges” and determining availability via difference with the target period. 最新_登壇資料詳細_Kaigi_on_Rails_2025_梅…
Mathematically:
Available = TargetPeriod − Union(UnavailablePeriods)
This transforms business logic into algebra over intervals.
The Limitation of PostgreSQL Range Types

PostgreSQL supports range types such as:
- tsrange (timestamp range)
- daterange
- int4range
But there is a critical limitation:
👉 A range represents only a single continuous interval.
Consider subtracting a sub-interval:
12:00–13:00 − 12:10–12:40
The true result is:
12:00–12:1012:40–13:00
Two separate intervals.
Standard range types cannot represent this, producing an error:
ERROR: result of range difference would not be contiguous
最新_登壇資料詳細_Kaigi_on_Rails_2025_梅…
The Breakthrough: Multirange (PostgreSQL 14+)
Multirange types solve this limitation by allowing multiple disjoint intervals to be stored as a single value.
Available multirange types include:
- int4multirange
- datemultirange
- tsmultirange
They allow discontinuous intervals to be handled as one logical entity. 最新_登壇資料詳細_Kaigi_on_Rails_2025_梅…
Conceptually:
{ [12:00–12:10), [12:40–13:00) }
Now subtraction works correctly.
Powerful Operations
Multirange supports the same operators as regular ranges:
- Overlap
- Intersection
- Difference
- Containment

Example:
SELECT int4multirange(1, 10) - int4multirange(5, 7);-- Result: {[1,5), [7,10)}
最新_登壇資料詳細_Kaigi_on_Rails_2025_梅…
This makes it ideal for availability calculations.
The Availability Algorithm
The chocoZAP system computes availability using the following pipeline:
- Aggregate all unavailable periods into a multirange
- Convert the query period into a multirange
- Subtract unavailable intervals
- Expand the result into individual ranges
最新_登壇資料詳細_Kaigi_on_Rails_2025_梅…
The output is an exact list of available time windows.
Integrating Multirange with Rails
Here’s an important practical detail:
👉 Rails does not natively support PostgreSQL multirange types.
The team adopted a clean architecture:
Perform all multirange logic in SQL using a VIEW
Strategy:
- Store individual intervals as standard ranges
- Use range_agg() to build multiranges
- Compute availability in SQL
- Use unnest() to convert results back to simple ranges
- Expose the view as a Rails model
最新_登壇資料詳細_Kaigi_on_Rails_2025_梅…
Example usage:
room.reservation_availabilities# => list of available time ranges
Complex math remains in the database; application code stays simple.
Beyond Booking Systems
The presentation highlights many other domains where multirange shines:
- Subscription periods with pauses
- Workforce scheduling
- Streaming session tracking
- Loan or rental systems
- Incident uptime calculations
最新_登壇資料詳細_Kaigi_on_Rails_2025_梅…
Any domain involving fragmented time intervals can benefit.
Why This Approach Matters
This case study illustrates a broader engineering principle:
👉 When a problem is inherently mathematical, model it mathematically.
Instead of writing intricate procedural logic, you can:
- Express constraints declaratively
- Leverage database primitives
- Reduce bugs and edge cases
- Improve performance
- Simplify application code
Multirange turns messy temporal logic into clean set operations.
Note: Multirange is a PostgreSQL feature. The Rails aspect discussed here focuses on integration patterns when ActiveRecord lacks native support.
Final Thoughts
PostgreSQL’s multirange types are one of the most underutilized features in modern backend development. Combined with Rails and SQL views, they enable highly expressive solutions to problems that would otherwise require complex custom algorithms.
As real-time systems, IoT platforms, and flexible scheduling services become more common, this approach is likely to grow in importance.
For Rails engineers building anything involving availability, time windows, or fragmented intervals, multirange is a tool worth mastering.

