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

comments powered by Disqus