.

Coffee Powered

code and content

Graceful degredation: Using Gravatar as a fallback avatar with Paperclip

Lots of people use Paperclip for stuff like letting their users upload avatars. This is great – Paperclip is easy to use, quick to integrate, and painless to maintain.

However, Gravatar has a great selling point: The user gets an avatar without ever having to go set one on your site. They have an identity established the moment they sign on. You’ve seen it in WordPress blogs (including this one!) and in products like Redmine – you just enter your name and email to comment, and you automagically have your Gravatar show up next to your post.

Fortunately, Paperclip is flexible enough to let us integrate Gravatars without too much of a hassle.

class User < ActiveRecord::Base
	# Paperclip lets you specify custom interpolations for your paths and such. We're going to exploit that!
	Paperclip::Attachment.interpolations[:gravatar_url] = proc do |attachment, style|
		# Suck out the size of the thumbnail. Assumes square thumbnails!
		# If we can't find the size data for whatever reason, the gravatar_url default will pick a size.
		size = nil
		if size_data = attachment.styles[style].first then
			if thumb_size = size_data.match(/\d+/).to_a.first then
				size = thumb_size.to_i
			end
		end
		attachment.instance.gravatar_url(nil, size)
	end

	# Paperclip macro - the important bit is the :default_url, with some extra sauce in the :styles
	has_attached_file(:avatar,
		:url => "/images/avatars/:id/:style_:basename.:extension",
		:path => ":rails_root/public/images/avatars/:id/:style_:basename.:extension",
		:default_url => ":gravatar_url",
		:default_style => :regular,
		:styles => {
			:tiny => "16x16#",
			:small => "20x20#",
			:regular => "25x25#",
		}
	)

	# Constructs a gravatar URL from size information. We can pass in a custom default image URL, if we want.
	# This assumes you have an "email" field on your model!
	def gravatar_url(default = "", size = 100)
		hash = Digest::MD5.hexdigest(email.downcase.strip)[0..31]
		"http://www.gravatar.com/avatar/#{hash}.jpg?size=#{size}&d=#{CGI::escape default}"
	end
end

Let’s try it out.

# Load a user with an avatar set...
>> u.avatar(:regular).url
=> "/images/avatars/2/regular_PB070175.jpg"

# Now nil the avatar...
>> u.avatar = nil
=> nil

# Reload, and check it out, Gravatar URL!
>> u.save; u.reload
=> nil
>> u.avatar(:regular).url
=> "http://www.gravatar.com/avatar/7448d375a321d33eecef61c7176246ef.jpg?size=25&d="

Sweetness. Default avatars for new users if they have a Gravatar, but they can set a custom one if they want, or if they’ve never set a Gravatar.

One thing you might want to do is to provide a non-Gravatar default image. That’s pretty easy with a few tweaks to the code we’ve set up.

First, you need a series of default avatars, one for each size that your user avatars can be. Name them after your styles, of course, so you’ll have something like:

/images/avatars/default/tiny.png
/images/avatars/default/small.png
/images/avatars/default/regular.png

Then, you’ll adjust your custom interpolator:

	DEFAULT_AVATAR_URL = "http://www.yourhost.com/images/avatars/default/%s.png"
	Paperclip::Attachment.interpolations[:gravatar_url] = proc do |attachment, style|
		size = nil
		if size_data = attachment.styles[style].first then
			if thumb_size = size_data.match(/\d+/).to_a.first then
				size = thumb_size.to_i
			end
		end
		attachment.instance.gravatar_url(sprintf(DEFAULT_AVATAR_URL, style), size)
	end

There are additional hacks you could do by including AssetTagHelper into your model in order to take advantage of asset load balancing in Rails and to avoid having to hard-code your site’s URL, but that gets a little messy, and is a post for another day.

In the meantime, enjoy your increased user engagement!

4 Comments

  1. February 15, 2009 at 7:38 pm | Permalink

    My Avatar gem does exactly this. You can find the gem at http://github.com/gcnovus/avatar and a usage example at http://github.com/gcnovus/pinball

  2. February 18, 2009 at 2:41 pm | Permalink

    We've taken the same approach with the Kete open source Rails app (http://kete.net.nz/ and http://github.com/kete/kete/ for source), though it is up to a site admin if they want to enable gravatar only, user portraits only (our name for avatars since they have broader functionality), neither, or both. If you enable both, the local user portrait will take precedence if it exists.

    We use attachment_fu and the avatar gem.

  3. February 23, 2009 at 4:24 pm | Permalink

    Awesome Post!

    I am going to use this right away for the next release of an app I am working on. Thanks a lot!

    Kent

  4. rsturim
    March 12, 2009 at 8:19 am | Permalink

    I'm a big fan of this, thanks for the article!

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*