Forum: Ruby on Rails Tag Cloud on rails?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Mike D. (Guest)
on 2007-02-14 01:24
Hi:

Anyone know of anyone that's implemented AND made available a tag cloud
implemented in rails?

Thanks!

Mike
Michael S. (Guest)
on 2007-02-14 01:59
(Received via mailing list)
On Wednesday 14 February 2007, Mike D. wrote:
> Hi:
>
> Anyone know of anyone that's implemented AND made available a tag
> cloud implemented in rails?

Here's what I'm using with Acts As Taggable (On Steroids).

I've added a method to the Tag model class for retrieving the N most
popular tags

  def self.find_most_popular(max_count = 0)
    count_col = Tag.connection.quote_column_name('count')
    sql =   "SELECT tags.id AS id, tags.name AS name, COUNT(*) AS
#{count_col}"
    sql <<  " FROM taggings JOIN tags ON taggings.tag_id = tags.id"
    sql <<  " GROUP BY tag_id ORDER BY #{count_col} DESC"
    sql <<  " LIMIT #{max_count.to_i}" if max_count.to_i > 0
    tags = Tag.find_by_sql(sql)
    tag_count = tags.size
    tags.each do |tag|
      tag.send(:write_attribute, :percentage, (tag.count * 100) /
tag_count)
    end
    tags
  end

Acts As Taggable On Steroids has some other functionality for this, see
its REAME.

In the PopularTagsHelper I have a method like this

  def popular_tag(t, options = {})
    wrap = options[:wrap] || 'span'
    font_size   = t.percentage * (options[:size_scale]   || 12)
    font_weight = t.percentage * (options[:weight_scale] || 10)
    font_size   = [font_size, options[:min_size]].max if
options[:min_size]
    font_size   = [font_size, options[:max_size]].min if
options[:max_size]
    content_tag(wrap,
      link_to(t.name, ''),
      :title => "#{t.count} times",
      :class => options[:class],
      :style => "font-size:#{font_size}%;font-weight:#{font_weight}%"
    )
  end

In the view

  <ul class="tagcloud">
  <% @popular_tags.sort_by(&:name).each do |t| -%>
    <%= popular_tag(t, :wrap => 'li', :min_size => 30, :max_size =>
400) %>
  <% end -%>
  </ul>

Finally some CSS

.tagcloud {
  text-align: center;
  width: 70%;
}
.tagcloud li {
  display: inline-block;
  display: -moz-inline-box;
  white-space: nowrap;
  vertical-align: middle;
  line-height: 1.2em;
  padding: 0 0.2em;
}


On a self-serving note, let me point you to
http://schuerig.de/michael/blog/index.php/2007/02/...

HTH,
Michael

--
Michael S.
mailto:removed_email_address@domain.invalid
http://www.schuerig.de/michael/
Chris T (Guest)
on 2007-02-14 12:13
(Received via mailing list)
Mike D. wrote:
> Hi:
>
> Anyone know of anyone that's implemented AND made available a tag cloud
> implemented in rails?
>
> Thanks!
>
> Mike
>
>
Like Michael, I'm using acts_as_taggable and adding a method to the Tag
model but implementing it slightly differently. I'm pasting the code as
is (and just looking at it fresh, it could be improved in places), but
not all of it is needed (e.g. I needed to be able to restrict the tag
cloud to certain models, and those lines are commented as optional

  def self.tag_cloud_count(options={})
    except, only = options[:except].to_a, options[:only].to_a # optional
    raise ArgumentError, "You can only specify :except OR :only options"
if !except.empty? && !only.empty? # optional
    conditions = "taggings.tag_id = tags.id" if except.empty? &&
only.empty?
    conditions = ["(taggings.tag_id = tags.id) AND
(taggings.taggable_type IN (?))", only.collect {|m| m.to_s.classify }]
if !only.empty? # optional
    conditions = ["(taggings.tag_id = tags.id) AND
(taggings.taggable_type NOT IN (?))", except.collect {|m|
m.to_s.classify }] if !except.empty? # optional
    find(:all, :select => "tags.*, COUNT(*) AS tag_count", :joins =>
"INNER JOIN taggings", :conditions => conditions, :group => "tags.name",
:order => "tags.name ASC")
  end

Then in my app helper:
  def tag_cloud_for(tag_cloud)
    max_tag_count = tag_cloud.max {|a,b| a.tag_count.to_i <=>
b.tag_count.to_i }.tag_count.to_f
    min_tag_count = tag_cloud.min {|a,b| a.tag_count.to_i <=>
b.tag_count.to_i }.tag_count.to_f
    min_font_size = 1.0
    max_font_size = 2.5
    mult = (max_font_size - min_font_size)/(max_tag_count -
min_tag_count)
    output = tag_cloud.collect { |tag| link_to( tag.name,
                                                {:controller =>
'search', :tag => tag.name},
                                                {:style => "font-size:
#{(((tag.tag_count.to_f - min_tag_count) * mult) + min_font_size)}em"})
}
    output.join(" ")
  end

In the helper method above the argument of the method is simply the
collection of tags returned by to tag_cloud_count method. The cloud is
output as a set of links, which go to my search controller, which
returns all items tagged with the given term.

Of course, YMMV, but hopefully between this and Michael's solution you
should be able to find something that suits.

Cheers
Chris
This topic is locked and can not be replied to.