How to not use constants in Rails (when dealing with time)

Lorenzo Sinisi bio photo By Lorenzo Sinisi Comment

There is a tendency among Ruby on Rails developers to specify time in constants. But this practice is quite dangerous and a bit obscure.

A classic example:

class Example
  ONE_SEC_AGO = 1.second.ago # will this be relative to the call of the class
  # or will it be a fixed time, for ever?

  def delete_outdated
    if created_at < ONE_SEC_AGO
      # do something dangerous
    end
  end

end

What do you expect to happen there the first time you run this code? And what will happen 10 minutes later?

In Rails the code will get loaded at the startup and executed every time it is needed, but a constant is a constant and it is not supposed to change (obviously). And if the constant will not change, 1.second.ago, after 10 minutes will be 10 minutes and 1 second ago; the same will happen after one month or two. And this is probably not the behaviour that the developer expected when assigning ‘1.second.ago’ to the constant ONE_SEC_AGO.

How to fix that?

Instead of using a constant, use a method (and private):

class Example

  def delete_outdated
    if created_at < one_sec_ago # the method will return the expected time, relatively
      # do something dangerous
    end
  end

  private

  def one_sec_ago
    1.second.ago
  end

end

Or if you really wanna use a constant:

class Example

  OUTDATED_AFTER = 1 # just as a number

  def delete_outdated
    if created_at < OUTDATED_AFTER.seconds.ago # and then you specify that this is time, seconds
      # do something dangerous
    end
  end
end

:+1:

comments powered by Disqus