17 June 2011

Display Avatar in Ruby on Rails application

Now a days displaying Avatar is a common trend in web technology. Avatar is graphical representation of an user. Thanks go to Tom Preston Werner for introducing Gravatar , a great web service which give globally recognized avatar. You just need to open up an account out their with an email address and upload your photo. Different websites, consuming Gravatar's service can display your photo if you register out there with the same email address.

In this example I will show you a way to display Gravatar in your Ruby on Rails web application.

First I will write a helper method which will return an image url for displaying Avatar. Gravater, id is simply the MD5 hexdigest of the email address. So the line returning avatar id will be:
gravatar_id = Digest::MD5.hexdigest(user.email.downcase)

I would like to display the avatar as 48x48, which is the usual size of a twitter display image. Also, I want to show a default image url if avatar is not shown. For these two, we need to pass some extra parameters. The method will look like:

def avatar_url(user)
    default_url = "#{root_url}images/default-image.jpg"
        gravatar_id = Digest::MD5.hexdigest(user.email.downcase)
        return "http://gravatar.com/avatar/#{gravatar_id}.png?s=48&d=#{CGI.escape(default_url)}"
      return default_url
In your view:

<%= link_to(image_tag(avatar_url(user)), user_path(user.id))%>

The above line, will show the avatar and will take you to the show method of UsersController if you click on it.

You can also choose from an user to display his avatar from gravatar or your local file system. All you need to do is to have a boolean field 'avatar' in your User table and re-arrange the logic in avatar_url method.

It's that simple! Happy coding!!

05 March 2011

SEO friendly URL in ruby on rails and friendly_id

By default Rails generate URL with ID. In short to_param method returns a string, which Action Pack uses for constructing an URL to this object. The default implementation returns records’ id as a string.
Suppose, we have a Category model. The routes.rb will look like:
map.resources :categories
In categories.rb controller:
@category = Category.find(1)
In view index.html.erb:
This will generate the URL: /category/1

While working on building a website Khan Academy In Bangla as a part of the translation project of Khan Academy , I realized that a SEO friendly URL is mandatory. In this website, I have categories like physics, biology or math and tutorials under each category. In order to make the user friendly URL I needed to overwrite to_param method in model.

In order to make it SEO friendly, in Category.rb model I added the line:
def to_param
  "#{id}-#{title.downcase.gsub(/[^a-zA-Z0-9]+/, '-').gsub(/-{2,}/, '-').gsub(/^-|-$/, '')}"
The regular expression will remove any special character. It generates the url: /category/1-biology. Looks better, right?
Although the URL has become SEO friendly now but this method has some drawbacks. To summarize some:

1. It appends the id with the name. If we remove ID, then maintaining uniqueness will be a problem
2. If the title field is edited then the URL will be changed causing SEO to break.
3. For a large application, it will not be feasible to overwrite to_param in tons of model.

In this point, I found a nice plugin/gem to make all these pretty simple and it is friedly_id . It will do all the work for you with some simple steps. For my system what I did were:
1. Install the gem:
gem install friendly_id
2. In environment.rb include the gem.
require 'friendly_id'
3. Generate friendly_id by going to my application directory:
cd khanacademybangla
script/generate friendly_id
4. Run the migration
rake db:migrate
5. Add has_friendly_id to the models which I am looking for to generate user friendly id
class Category < ActiveRecord::Base
has_friendly_id :title, :use_slug => true
6. Run a rake task to generate slugs for existing records:
rake friendly_id:make_slugs MODEL=ModelName
For my example it was:
rake friendly_id:make_slugs MODEL=category
That’s it! Now we will be able to see a completely SEO friendly url: /category/biology

I am yet to push my code to production! You need to wait till tomorrow to see it live.