Module | ActiveRecord::Acts::Taggable::ClassMethods |
In: |
lib/taggable.rb
|
This mixin provides an easy way for adding tagging capabilities (also known as folksnomy) to your active record objects. It allows you to add tags to your objects as well as search for tagged objects.
It assumes you are using a fully-normalized tagging database schema. For that, you need a table (by default, named tags) to hold all tags in your application and this table must have a primary key (normally a id int autonumber column) and a name varchar column. You must also define a model class related to this table (by default, named Tag).
All tag names will be stored in this tags table. Taggable objects should reside in their own tables, like any other object. Tagging objects is performed by the acts_as_taggable mixin using a has_and_belong_to_many relationship that is automatically created on the taggable class, and as so, a join table must exist between the tags table and the taggable object table.
The name of the join table follows the standards for rails
Unless the join table is explicitly specified as an option, it is guessed using the lexical order of the class names.
The join table must be composed of the foreign keys from the tags table and the taggable object table, so for instance, if we have a tags table named tags (related to a Tag model) and a taggable photos table (related to a Photo model), there should be a join table tags_photos with int FK columns photo_id and tag_id. If you dont use a explicit full model related to the join table (through the +:join_class_name+ option), you must not add a primary key to the join table.
The acts_as_taggable adds the instance methods tag, tag_names, +tag_names= +, +tag_names<< +, +tagged_with? + for adding tags to the object and also the class method find_tagged_with method for search tagged objects.
Examples:
class Photo < ActiveRecord::Base # this creates a 'tags' collection, through a has_and_belongs_to_many # relationship that utilizes the join table 'photos_tags'. acts_as_taggable :normalizer => Proc.new {|name| name.downcase} end photo = Photo.new # splits and adds to the tags collection photo.tag "wine beer alcohol" # don't need to split since it's an array, but replaces the tags collection # trailing and leading spaces are properly removed photo.tag [ 'wine ', ' vodka'], :clear => true photo.tag_names # => [ 'wine', 'vodka' ] # You can remove tags one at a time or in a group photo.tag_remove 'wine' photo.tag_remove 'wine beer alcohol' # appends new tags with a different separator # the 'wine' tag wont be duplicated photo.tag_names << 'wine, beer, alcohol', :separator => ',' # The difference between +tag_names+ and +tags+ is that +tag_names+ # holds an array of String objects, mapped from +tags+, while +tags+ # holds the actual +has_and_belongs_to_many+ collection, and so, is # composed of +Tag+ objects. photo.tag_names.size # => 4 photo.tags.size # => 4 # Now you can clear all tags in one call photo.clear_tags! # Find photos with 'wine' OR 'whisky' Photo.find_tagged_with :any => [ 'wine', 'whisky' ] # Finds photos with 'wine' AND 'whisky' using a different separator. # This is also known as tag combos. Photo.find_tagged_with(:all => 'wine+whisky', :separator => '+' # Gets the top 10 tags for all photos Photo.tags_count :limit => 10 # => { 'beer' => 68, 'wine' => 37, 'vodka' => '22', ... } # Gets the tags count that are greater than 30 Photo.tags_count :count => '> 30' # => { 'beer' => 68, 'wine' => 37 } # Replace allows you to find_tagged_with, remove the old tags and add the new ones Photo.replace_tag("beer whisky","wine vodka") # Display the photos returned from the tags_count call using 9 different CSS classes <% Photo.cloud(@photo_tags, %w(cloud1 cloud2 cloud3 cloud4 cloud5 cloud6 cloud7 cloud8 cloud9)) do |tag, cloud_class| %> <%= link_to(h("<#{tag}>"), tag_photos_url(:name => tag), { :class => cloud_class } ) -%> <% end %> # Display the photos returned from the tags_count call using 5 different font sizes <% Photo.cloud(@photo_tags, %w(x-small small medium large x-large)) do |tag, font_size| %> <%= link_to(h("<#{tag}>"), tag_photos_url(:name => tag), { style: => "font-size: #{font_size}" } ) -%> <% end %>
You can also use full join models if you want to take advantage of ActiveRecords callbacks, timestamping, inheritance and other features on the join records as well. For that, you use the +:join_class_name+ option. In this case, the join table must have a primary key.
class Person # This defines a class +TagPerson+ automagically. acts_as_taggable :join_class_name => 'TagPerson' end # We can open the +TagPerson+ class and add features to it. class TagPerson acts_as_list :scope => :person belongs_to :created_by, :class_name => 'User', :foreign_key => 'created_by_id' before_save :do_some_validation after_save :do_some_stats end # We can do some interesting things with it now person = Person.new person.tag "wine beer alcohol", :attributes => { :created_by_id => 1 } Person.find_tagged_with(:any => 'wine', :condition => "tags_people.created_by_id = 1 AND tags_people.position = 1")
This method defines a has_and_belongs_to_many relationship between the target class and the tag model class. It also adds several instance methods for tagging objects of the target class, as well as a class method for searching objects that contains specific tags.
The options are:
The +:collection+ parameter receives a symbol defining the name of the tag collection method and it defaults to +:tags+.
The +:tag_class_name+ parameter receives the tag model class name and it defaults to +’Tag’+.
The +:tag_class_column_name+ parameter receives the tag model class name attribute and it defaults to +’name’+.
The +:normalizer + paramater takes a Procs. This is used to normalize all tags Simple example :normalizer => Proc.new {|name| name.capitalize}
The +:join_class_name+ parameter receives the model class name that joins the tag model and the taggable model. This automagically defines the join model class that can be opened and extended.
The remaining options are passed on to the has_and_belongs_to_many declaration. The +:join_table+ parameter is defined by default using the standard has_and_belongs_to_many behavior.