Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Tagging for Ruby on Rails

branch: master

Fetching latest commit…

Octocat-spinner-32-eaf2f5

Cannot retrieve the latest commit at this time

Octocat-spinner-32 generators
Octocat-spinner-32 lib
Octocat-spinner-32 test
Octocat-spinner-32 .gitignore
Octocat-spinner-32 CHANGELOG
Octocat-spinner-32 MIT-LICENSE
Octocat-spinner-32 README
Octocat-spinner-32 Rakefile
Octocat-spinner-32 acts_as_taggable_on_steroids.gemspec
Octocat-spinner-32 init.rb
README
= 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 git://github.com/jviney/acts_as_taggable_on_steroids.git

== 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")
  
In your views you should use something like the following:

  <%= f.label :tag_list %>
  <%= f.text_field :tag_list, :size => 80 %>

=== 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

=== Auto-Complete AJAX Tag Fields in 6 easy steps!

  Assuming we want to tag our documents with auto-complete, this is how we do it.
  (Assumes Prototype, but I'm sure it can be done in a similar fashion with 'pick your fav js lib')

  # 1. Make the class taggable:
  class Document < ActiveRecord::Base
    acts_as_taggable
    # rest of class...
  end

  # 2. Need a route for the auto-complete AJAX to query (in config/routes.rb):
  map.resources :documents, :collection => { :tag_suggestions => :get }

  # 3. Migration for the cached lag list (in db/migrate):
  class CachedLagListDocuments < ActiveRecord::Migration
    def self.up
      add_column :documents, :cached_tag_list, :string, :default => nil
    end
    def self.down
      remove_column :documents, :cached_tag_list
    end
  end

  <!-- 4. The Form With Auto-Compelte Tag Field (in app/views/documents/new.html.erb)-->
  <% form_for(:document, :url => documents_path, :html => { :multipart => true }) do |form| %>
    <%= form.label(:tag_list, "Tag to categorize <strong>(separate by commas)</strong>") %><br/>
    <%= text_field_with_auto_complete :document, :tag_list,
                                      { :size => 40, :style => "width: 100%", :class => "bigger"},
                                      { :url => tag_suggestions_documents_path(:format => :js), :method => :get, :tokens => ',' } %>
    ... other fields ...
  <% end %>

  # 5. The action the auto-complete tag field on the form will query:
  class DocumentsController < ApplicationController
    protect_from_forgery :except => [:tag_suggestions]
    def tag_suggestions
      @tags = Tag.restrict_taggable_type("Document").find(:all, :conditions => ["name LIKE ?", "%#{params[:tag]}%"])
      render :layout => false
    end
  end

  # 6. The magic glue to pull it all together
  # Create a file in app/views/documents called tag_suggestions.js.erb and put this one line in it:
  <%= auto_complete_result @tags, :name %>

=== Other

Problems, comments, and suggestions all welcome. jonathan.viney@gmail.com  
Something went wrong with that request. Please try again.