TIL: Easily Support Gravatars in Rails

We’re building some software where we’d like to display avatars for email contacts even if they aren’t users of our software. While Gravatar is a relic of Web 2.0, we’ve found that there are still a significant number of people who have their email addresses in that system.

Here’s how I streamlined displaying an avatar for an email address if it exists in the Gravatar system.

First I created a new Gravatarable concern in app/models/concerns:

module Gravatarable
extend ActiveSupport::Concern

# Check if an image exists for the associated email hash.
# We cache this to avoid excessive HTTP calls.
def gravatar?
Rails.cache.fetch(gravatar_cache_key, expires_in: 2.weeks) do
response = Net::HTTP.get_response(URI(gravatar_url))
response.is_a?(Net::HTTPSuccess)
end
end

# Gravatar's image request docs:
# https://docs.gravatar.com/general/images/
#
# In our case, we want the request to 404 if Gravatar has no
# image associated with the email hash.
def gravatar_url(size:48)
"https://www.gravatar.com/avatar/#{gravatar_id}?s=#{size}&d=404"
end

private

def gravatar_cache_key
"Sender.email_address.#{email_address.downcase}.gravatar?"
end

def gravatar_id
Digest::MD5::hexdigest(email_address.downcase)
end

end

This concern gets included in our Contact model. It can be included in any model that has an email_address method:

class Contact < ApplicationRecord
include Gravatarable
...
end

Then a simple helper method can be used to display the avatar:

module ApplicationHelper
def avatar_for(contact, size:, alt: contact.name, hidden: false)
avatar_attributes = {
alt: alt,
title: alt,
aria: { hidden: hidden },
width: size,
height: size,
class: 'avatar'
}

image_src = contact.gravatar? ?
contact.gravatar_url(size: size) :
'avatar-default.png'
image_tag(image_src, avatar_attributes)
end