Use Ruby Range with date objects
Jeremy
Posted on April 27, 2022
It is quite common to need to define time periods in your application, most often it is modeled by a start date and an end date. Then these dates are compared to the current date for thing like knowing if a customer is a paying member.
This way of doing often results in methods that could be hard to read
class User
def paying_member?
subscription_started_at <= Date.current &&
(subscription_ended_at.nil? || subscription_ended_at > Date.current)
end
end
But there is a way to improve the readability of your code using the Ruby’s Range class.
class User
def paying_member?
subscription_period.cover?(Date.current)
end
private
def subscription_period
subscription_started_at..subscription_ended_at
end
end
In the event that the customer do not have terminated its subscription the subscription_period
will return an infinite Range which will also validate our predicate.
Now let’s say that business consider that the subscription is supposed to be over the day before its stored end date, it is quite simple to modify the subscription_period
method to return a Range that exclude its upper limit.
class User
# ...
def subscription_period
subscription_started_at...subscription_ended_at
end
end
In a Rails application, it is also possible to take advantage of the methods Range#===
and Range#overlaps?
added to the Range class by ActiveSupport.
class User
def subscriber_kind
case subscription_period
when innovator_period then 'Innovator'
when early_adopter_period then 'Early adopter'
when early_majority_period then 'Early majority'
when late_majority_period then 'Late majority'
when laggards_period then 'Laggard'
end
def share_subscription_with(user)
subscription_period.overlaps?(user.subscription_period)
end
end
Links
Posted on April 27, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.