Acts As Taggable Tag Cloud

If you are using the Ruby on Rails acts_as_taggable plugin you may want to display the top tags in a tag cloud. To generate a tag cloud you will to write some code beyond just writing the controller action. You will need to augment the taggable plugin itself and create a function in the application helper. Lets start by adding a new method in the Tag model provided by the acts_as_taggable plugin. Open the vendor/plugins/acts_as_taggable/lib/tag.rb file and add this method:

def self.tags(options = {})
  query = "select tags.id, name, count(*) as count"
  query << " from taggings, tags"
  query << " where tags.id = tag_id"
  query << " group by tag_id"
  query << " order by #{options[:order]}" if options[:order] != nil
  query << " limit #{options[:limit]}" if options[:limit] != nil
  tags = Tag.find_by_sql(query)
end

This method will return the id, name, and usage count for each tag. This method also provides a way to limit and order the tags. Once we have added the new method in the Tag model we will need to add a method to the application helper which will help in selecting the right style class for each tag. Add the following function to app/helpers/application_helper.rb:

def tag_cloud(tags, classes)
  max, min = 0, 0
  tags.each { |t|
    max = t.count.to_i if t.count.to_i > max
    min = t.count.to_i if t.count.to_i < min
  }

  divisor = ((max - min) / classes.size) + 1

  tags.each { |t|
    yield t.name, classes[(t.count.to_i - min) / divisor]
  }
end

The implementation for the tag_cloud method is based on the work done by Tom Fakes. With the tags method in the Tag model and the tag_cloud method in the application helper we can now focus on the controller and view. In the controller you can use the following bit of code to get the the first one hundred tags order by name:

@tags = Tag.tags(:limit => 100, :order => "name desc")

In the view we will use the tag_cloud method so that it will select the right css class based on the tag usage count. Here is the view code:

<% tag_cloud @tags, %w(nube1 nube2 nube3 nube4 nube5) do |name, css_class| %>
  <%= link_to name, {:action => :tag, :id => name},
    :class => css_class %>
<% end %>

Please note that nube1 through nube5 are css class names which will need to be defined in your stylesheet to generate the cloud effect. Just completeness sake here are my css classes:

.nube1 {font-size: 1.0em;}
.nube2 {font-size: 1.2em;}
.nube3 {font-size: 1.4em;}
.nube4 {font-size: 1.6em;}
.nube5 {font-size: 1.8em;}
.nube6 {font-size: 2.0em;}

Technorati Tags: , , , ,