Nithin Bekal About

Avoid time_ago_in_words in Rails

24 Jul 2015

ActiveSupport’s time_ago_in_words makes it really easy to display time as “x minutes/hours/months ago” format. However, it has one big disadvantage: it makes it harder to use fragment caching.

Let’s say we’re displaying posts within a partial:

<% # app/views/posts/_post.html.erb %>

<% cache post do %>
  <%= post.body %><br/>
  (posted <%= time_ago_in_words(post.created_at) %> ago)
<% end %>

Here the second line might show “posted 2 minutes ago” right now, but in a minute, it needs to change to “posted 3 minutes ago”, but it will keep showing the older time until the cache expires.

My preferred solution for this is to use the timeago jquery plugin. Timeago plugin requires time in ISO 8601 format, so we’ll add a helper method that renders a span containing time in the correct format.

# app/helpers/time_helper.rb

module TimeHelper
  def timeago(time)
    content_tag(:span, time.iso8601, title: time.iso8601, class: 'timeago')
  end
end

Let’s add a line of Javascript to convert all spans having the class timeago to the time ago in words format:

$('.timeago').timeago()

Now we can use this in the view, in place of time_ago_in_words:

<% # app/views/posts/_post.html.erb %>

<% cache post do %>
  <%= post.body %><br/>
  (posted <%= timeago(post.created_at) %> ago)
<% end %>

Not only does this allow you to use fragment caching correctly, but it also updates the time if you keep the page open for a while.

Hi, I’m Nithin! This is my blog about programming. Ruby is my programming language of choice and the topic of most of my articles here, but I occasionally also write about Elixir, and sometimes about the books I read. You can use the atom feed if you wish to subscribe to this blog or follow me on Mastodon.