Ruby ranges are very handy and efficient when you want to work with a sequence of numbers or characters bound by start and end values. But we could come across situations where we want ranges that either have no end value or start value. Ruby 2.6 introduced the concept of an endless range and later Ruby 2.7 brought in the beginless range.

Infinite Ranges in Ruby

As mentioned in the official Ruby docs, a beginless range and endless range represents a semi-infinite range.
A beginless range would look like (..3) Or (...3) while endless range looks like (3..) Or (3...) and effectively defines the maximum or minimum boundary of the range.

Infinite Ranges in Rails

Infinite ranges are supported in Rails while fetching records from the database as seen below:

Loading development environment (Rails 7.1.0.alpha)
irb(main):013:0> Event.where(date:  (..Time.now))
  Event Load (0.5ms)  SELECT "events".* FROM "events" WHERE "events"."date" <= ? /* loading for pp */ LIMIT ?  [["date", "2022-12-11 12:56:31.866828"], ["LIMIT", 11]]
=>
[#<Event:0x000055a3f20b22f0
  id: 1,                                                              
  date: Sun, 11 Dec 2022 12:32:57.255815000 UTC +00:00,               
  name: "The December Concert",                                       
  description: "The ultimate concert to end the year",                
  created_at: Sun, 11 Dec 2022 12:32:57.256643000 UTC +00:00,         
  updated_at: Sun, 11 Dec 2022 12:32:57.256643000 UTC +00:00>,
 #<Event:0x000055a3f20b2188
  id: 5,
  date: Mon, 31 Oct 2022 18:30:00.000000000 UTC +00:00,
  name: "The Halloween Festival",
  description: "The eve of All Saints Day",
  created_at: Sun, 11 Dec 2022 12:55:33.831731000 UTC +00:00,
  updated_at: Sun, 11 Dec 2022 12:56:21.981937000 UTC +00:00>]

The above query fetched all the past event records, i.e the ones with the date value less than the current time.

Loading development environment (Rails 7.1.0.alpha)
irb(main):014:0> Event.where(date:  (Time.now..))
  Event Load (0.2ms)  SELECT "events".* FROM "events" WHERE "events"."date" >= ? /* loading for pp */ LIMIT ?  [["date", "2022-12-11 12:56:43.438138"], ["LIMIT", 11]]
=>
[#<Event:0x000055a3f26616b0
  id: 2,
  date: Sat, 31 Dec 2022 18:30:00.000000000 UTC +00:00,
  name: "The New Year Event",
  description: "The first event of the year",
  created_at: Sun, 11 Dec 2022 12:34:23.292070000 UTC +00:00,
  updated_at: Sun, 11 Dec 2022 12:34:23.292070000 UTC +00:00>,
 #<Event:0x000055a3f26615e8
  id: 3,
  date: Thu, 12 Jan 2023 18:30:00.000000000 UTC +00:00,
  name: "The Lohri Festival",
  description: "The celebration of harvest festival",
  created_at: Sun, 11 Dec 2022 12:36:13.234757000 UTC +00:00,
  updated_at: Sun, 11 Dec 2022 12:37:13.423191000 UTC +00:00>]

The above query fetched all the future event records, i.e the ones with the date value greater than the current time.

In addition to using ranges for fetching records, we generally use them in Rails with the Active Record length and inclusion validators.

With Rails < 7.1.0-alpha

If we use infinite range in a validator like:

class Event < ApplicationRecord
  ...
  validates_length_of :name, in: (..30)
  ...
end

it throws an error as follows:

Loading development environment (Rails 7.0.1)
irb(main):001:0> Event
Traceback (most recent call last):
        3: from (irb):1
        2: from app/models/event.rb:4:in `<main>'
        1: from app/models/event.rb:7:in `<class:Event>'
RangeError (cannot get the minimum of beginless range)

The only way to validate is by passing maximum or minimum value to the validates method as follows:

validates_length_of :name, maximum: 30, allow_blank: true

With Rails >= 7.1.0-alpha

With the two PRs that were merged recently - PR#45123 and PR#45138, it is possible to pass beginless/endless ranges to the length and inclusivity validators with the in/within options.

  # Allows date to be either today's or any future date but not a past date
  validates_inclusion_of :date, in: -> { (Date.today..) } 
  # Allows name to be nil or of a max length of 30 characters
  validates_length_of :name, in: (..30)

  # Mandates description to be of minimum 10 characters with no max limit
  validates_length_of :description, in: (10..)

Please note: These changes are available in the alpha phase of Rails 7.1.0 at the time of writing this article. To get the 7.1.0-alpha version, you have to specify the rails main branch in Gemfile -

    # Gemfile
    gem 'rails', github: 'rails/rails', branch: 'main'

References