Nithin Bekal

Posts About Notes Slides

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 Bekal. I work at Shopify in Ottawa, Canada. Previously, co-founder of CrowdStudio.in and WowMakers. Ruby is my preferred programming language, and the topic of most of my articles here, but I'm also a big fan of Elixir. Tweet to me at @nithinbekal.