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: , , , ,

Related posts:

  1. Acts As Taggable Conditions Hack
  2. Acts As Taggable Plugin
  3. Acts As Bookmarkable Plugin
  4. Acts As Commentable Plugin
  5. Acts As Voteable Rails Plugin

This entry was posted in CSS, Ruby, TechKnow. Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

12 Comments

  1. Posted January 19, 2007 at 12:23 am | Permalink

    Nice and simple. That’s how I like it. Other tag cloud posts over complicate it for no reason. Good work.

  2. Posted January 20, 2007 at 12:59 pm | Permalink

    Nice but I think the tag_cloud has a little bug. The min value will never change from 0, as no count of tag can be less than zero.
    I bet you have to start the min value with a count value of any tag at first time.

  3. Posted February 9, 2007 at 12:21 am | Permalink

    I think the ordering would be better like this:

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

    Otherwise you’re limiting the tags displayed by just the number whereas its probably much more useful to display the 100 most popular tags

  4. Posted February 9, 2007 at 12:39 am | Permalink

    Please ignore my previous comment. This is what I really meant. This gets the top 100 most popular tags and then sorts them by name ignoring cases so capitals don’t show up before all the lower case tags.

    @tags = Tag.tags(:order => "count DESC, name",
      :limit => 100).sort_by { |tag| tag.name.downcase }
    
  5. Posted February 12, 2007 at 12:10 pm | Permalink

    @Brian – Thanks for your comment. Is it nice that one line can do soo much?

  6. Posted February 16, 2007 at 5:26 am | Permalink

    Really cool…
    I like it very much.

    it works for acts_as_taggable_on_steroids too,

    but you don’t have to add def self.tags(options = {}) to vendor/plugins/acts_as_taggable/lib/tag.rb

    so you just call
    @tags = Post.tag_counts(:limit => 100, :order => “name desc”) instead
    or @tags = Product.tag_counts

  7. Posted March 22, 2007 at 2:07 pm | Permalink

    You can employ more than one color with discretion.

    One way to use colors in your cloud tag:
    - select a main color, assign it to the biggest font;
    - “blend” this color for smaller fonts.
    A “coloring” example at

    http://www.featurepics.com/editorial/tag-cloud.aspx

    Great article. Thanks a lot!

  8. Nicolas
    Posted June 4, 2007 at 1:42 pm | Permalink

    Thanks a lot!

    I want to get the number of tags displayed in my tagcloud. Can someone help me out?

  9. Posted July 22, 2007 at 11:34 pm | Permalink

    I have made a small modification to pull out tags for a particular taggable_type and build a tag cloud only for that type. Useful in applications where multiple kinds of objects are being tracket

    You can find the write up here

  10. Posted August 7, 2007 at 8:44 am | Permalink

    As rds says, the min value should be initialized to something. I initialize it to tags[0].count.to_i

    without that once the tag count for some tag goes above a certain value, wierd things happen (all tags show up with same smallest font)

  11. Posted January 13, 2009 at 2:23 pm | Permalink

    @frederico, What works in acts_as_taggable_on_steriods is:

    @tags = Tag.counts(:order => “count DESC, name”,
    :limit => 100).sort_by { |tag| tag.name.downcase }

  12. Posted March 10, 2011 at 1:29 am | Permalink

    Hey, thanks. Still working in 2011 :)

    One thing I’ve changed is that I prefer to declare “classes” like this in the tag_clouds helper

    classes = (1..6).collect { |i| “nube#{i}” }

    instead of passing them from the view.

5 Trackbacks

  1. [...] à notre helpers/cd_helper.rb. Cette méthode n’est pas de moi , je l’ai trouvée sur ce très bon article du blog Juixe [...]

  2. [...] to create a tag cloud in a Rails [...]

  3. By Tagging at AmigoFisher on October 8, 2007 at 8:54 pm

    [...] I wanted the tagging to be per user ala deli.cio.us or flickr but then with global tag clouds, etc. I used the standard legacy acts_as_taggable plugin with the per user tagging modifications and the even further mods. I looked at acts_as_taggable_on_steroids but found that the original one suited my needs better. I also used this tag cloud code. [...]

  4. [...] Juixe TechKnow » Acts As Taggable Tag Cloud ruby on rails, rails, rails plugins, acts_as_taggable, tag cloud [...]

  5. [...] http://www.juixe.com/techknow/index.php/2006/07/15/acts-as-taggable-tag-cloud/ http://agilewebdevelopment.com/plugins/acts_as_taggable_on_steroids [...]

Post a Comment

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

*
*