Overriding methods as a Rubyist is extremely natural and powerful. Recently, I did run into a circumstance where I had an ActiveRecord object with a DateTime that I needed in a specific TimeZone (based on user input). If you ever have tried to override the getter for an attribute with the same name and have been stumped, this article details one way of making it work.
Alright, first off some example data to support our solution.
=> Event
id: 1
name: "How to be a pro Rubyist?"
start_time: Mon, 02 Jul 2018 14:11:17 EDT -04:00
time_zone: "UTC"
With the above, anytime I wanted to output the Event’s start_time
to the front-end I would need to reach
for in_time_zone.
in_time_zone
Returns the simultaneous time in Time.zone, or the specified zone. - apidock.com, Ruby on Rails
Here’s an example of outputting the Event object’s start_time
in the proper
time zone:
<% event = Event.find(1) %>
<%= event.start_time.in_time_zone(event.time_zone) %>
Quite, verbose no?
Well what if we just override the Event#start_time
getter to already
perform the conversion?
class Event
def start_time
start_time.in_time_zone(time_zone)
end
end
Nope! This will result in the dreaded SystemStackError: stack level too deep
, which basically translated to not having a proper stop condition in a recursion loop. Or in our case overriding a method and using the same method name within it.
But all hope is not lost. read_attribute
to the rescue!
Read Attribute
read_attribute allows you to return the value from ActiveRecord before it makes it to the getter method. Perfect! Here’s the new working solution.
class Event
...
def start_time
read_attribute(:start_time).in_time_zone(time_zone)
end
end
We’ve now successfully overridden a named attribute using the value from the same attribute. Neat!
Got any other Ruby method tricks? Is there a better way to accomplish the above? Leave me a comment below.
Join the conversation