= acts_as_taggable_on_steroids If you find this plugin useful, please consider a donation to show your support! http://www.paypal.com/cgi-bin/webscr?cmd=_send-money Email address: jonathan.viney@gmail.com == Instructions This plugin is based on acts_as_taggable by DHH but includes extras such as tests, smarter tag assignment, and tag cloud calculations. == Installation ruby script/plugin install http://svn.viney.net.nz/things/rails/plugins/acts_as_taggable_on_steroids == Usage === Prepare database Generate and apply the migration: ruby script/generate acts_as_taggable_migration rake db:migrate === Basic tagging Let's suppose users have many posts and we want those posts to have tags. The first step is to add +acts_as_taggable+ to the Post class: class Post < ActiveRecord::Base acts_as_taggable belongs_to :user end We can now use the tagging methods provided by acts_as_taggable, <tt>#tag_list</tt> and <tt>#tag_list=</tt>. Both these methods work like regular attribute accessors. p = Post.find(:first) p.tag_list # [] p.tag_list = "Funny, Silly" p.save p.tag_list # ["Funny", "Silly"] You can also add or remove arrays of tags. p.tag_list.add("Great", "Awful") p.tag_list.remove("Funny") === Finding tagged objects To retrieve objects tagged with a certain tag, use find_tagged_with. Post.find_tagged_with('Funny, Silly') By default, find_tagged_with will find objects that have any of the given tags. To find only objects that are tagged with all the given tags, use match_all. Post.find_tagged_with('Funny, Silly', :match_all => true) See <tt>ActiveRecord::Acts::Taggable::InstanceMethods</tt> for more methods and options. === Tag cloud calculations To construct tag clouds, the frequency of each tag needs to be calculated. Because we specified +acts_as_taggable+ on the <tt>Post</tt> class, we can get a calculation of all the tag counts by using <tt>Post.tag_counts</tt>. But what if we wanted a tag count for an single user's posts? To achieve this we call tag_counts on the association: User.find(:first).posts.tag_counts A helper is included to assist with generating tag clouds. Include it in your helper file: module ApplicationHelper include TagsHelper end You can also use the <tt>counts</tt> method on <tt>Tag</tt> to get the counts for all tags in the database. Tag.counts Here is an example that generates a tag cloud. Controller: class PostController < ApplicationController def tag_cloud @tags = Post.tag_counts end end View: <% tag_cloud @tags, %w(css1 css2 css3 css4) do |tag, css_class| %> <%= link_to tag.name, { :action => :tag, :id => tag.name }, :class => css_class %> <% end %> CSS: .css1 { font-size: 1.0em; } .css2 { font-size: 1.2em; } .css3 { font-size: 1.4em; } .css4 { font-size: 1.6em; } === Caching It is useful to cache the list of tags to reduce the number of queries executed. To do this, add a column named <tt>cached_tag_list</tt> to the model which is being tagged. The column should be long enough to hold the full tag list and must have a default value of null, not an empty string. class CachePostTagList < ActiveRecord::Migration def self.up add_column :posts, :cached_tag_list, :string end end class Post < ActiveRecord::Base acts_as_taggable # The caching column defaults to cached_tag_list, but can be changed: # # set_cached_tag_list_column_name "my_caching_column_name" end The details of the caching are handled for you. Just continue to use the tag_list accessor as you normally would. Note that the cached tag list will not be updated if you directly create Tagging objects or manually append to the <tt>tags</tt> or <tt>taggings</tt> associations. To update the cached tag list you should call <tt>save_cached_tag_list</tt> manually. === Delimiter If you want to change the delimiter used to parse and present tags, set TagList.delimiter. For example, to use spaces instead of commas, add the following to config/environment.rb: TagList.delimiter = " " === Unused tags Set Tag.destroy_unused to remove tags when they are no longer being used to tag any objects. Defaults to false. Tag.destroy_unused = true === Other Problems, comments, and suggestions all welcome. jonathan.viney@gmail.com