Plugins - acts_as_taggable_redux
Add to favoritesActsAsTaggableRedux
=============
Allows for user owned tags to be added to multiple classes, and makes tags easier to work with.
Prerequisites
=======
Install Edge Rails before you get started so you get RESTful routing.
ActsAsTaggableRedux depends on database tables to store tagging information. Create the migration for these tables with this command:
rake acts_as_taggable:db:create
Then run the migration to create the tables with this command:
rake db:migrate
Also you will need to add this to your user model:
acts_as_tagger
OPTIONAL: The helper functions assume the pressence of a tags controller, that is what the tag clouds and tags will link to.
OPTIONAL: To pretty up tag clouds and lists you can generate an example stylesheet with this command:
rake acts_as_taggable:stylesheet:create
and then include this in your layouts that have tag clouds:
<%= stylesheet_link_tag 'acts_as_taggable_stylesheet' %>
Example
=
The following is an example of how you might integrate tags with an Item model.
config/routes.rb
may.resource :items, :tags
app/views/items/new.erb
New Item
<% form_for(:item, @item) do |f| -%>
<%= error_message_for :item %>
Tags: <%= f.text_field :tag_list -%>
<%= submit_tag "Save" -%>
<% end -%>
if you want users to own taggings change the tags line to this
Tags: <%= f.text_field :tag_list, :value => @item.tag_list(user) -%>
and add this line beneath it
<%= f.hidden_field :user_id, :value => user.id -%>
app/views/items/show.erb
Item tagged with:
<% item.tags.each do |tag| -%>
<%= link_to_tag(tag) %>
<% end -%>
app/views/items/edit.erb
New Item
<% form_for(:item, @item, :html => { :method => :post }) do |f| -%>
<%= error_messages_for :item %>
Tags: <%= f.text_field :tag_list -%>
<%= submit_tag "Save" -%>
<% end -%>
app/controllers/items_controller.rb
class ItemController < ApplicationController
def new
@item = Item.new
end
def create
@item = Item.new(params[:item])
respond_to do |format|
if @item.save
flash[:notice] = 'Item was successfully created.'
format.html { redirect_to item_url(@item) }
format.xml { head :created, :location => item_url(@item) }
else
format.html { render :action => "new" }
format.xml { render :xml => @item.errors.to_xml }
end
end
end
def show
@item = Item.find(params[:id], :include => :tags)
end
def edit
@item = Item.find(params[:id])
end
def update
@item = Item.find(params[:id])
respond_to do |format|
if @item.update_attributes(params[:item])
flash[:notice] = 'Item was successfully updated.'
format.html { redirect_to item_url(@item) }
format.xml { head :updated, :location => item_url(@item) }
end
format.html { render :action => "edit"}
format.xml { render :xml => @item.errors.to_xml}
end
end
end
Tag clouds
====
Tag clouds are created by a helper function, and depend on the counter cache to get fast accurate counts. To ensure this keeps working properly, don’t add new tags to a taggable in any way other than using the tag.tag(taggable) style. This will ensure that the caches don’t lose track. Also, see the prerequisites for installing the stylesheet so that the tag cloud actually looks like a tag cloud. Otherwise, just pop into a view that you want the tag cloud to appear and type this:
<%= tag_cloud %>
Copyright © 2007 monki(Wesley Beary), released under the MIT license

It seems that the svn repository is not updated. There seems to be an updated repository in github: http://github.com/monki/actsas_taggableredux/
to get the migration generator to work with rails 2.1, I had to change tasks/actsas_taggabletasks.rake and add
require 'environment'
before require 'rails_generator'
hat tip to: http://d.hatena.ne.jp/kusakari/20080721/1216634680
How can I generate a tag cloud per user? Is it possible?
Thanks
Or - if the moderator prefers - here are changes I made in a blog post http://mudabone.com/aietc/?p=762
Thanks for the plugin! A few additions is it helps anyone:
1) Need to add "acts_as_taggable" to model being tagged (items in your example)
2) Modified findtaggedwith to work with will_paginate plugin
3) Modified helper for better seo - added this to ActsAsTaggableHelper
def tag_url(tag) "/tags/#{tag.name}" end
4) Added delicious styled tagging form helper to do this: a) add this to ActsAsTaggableHelper def delicious_tags(obj, f) res = %(<br/><b>Tags:</b> #{f.textfield :taglist}) res << %(<div style="border:solid 1px; margin:10px; padding:10px;">) res << spacedtagsdelicious(obj) res << "</div>" return res end
def spacedtagsdelicious(obj) res = [] Tag.find(:all, :order => "name").each do |tag| link = %(javascript:swaptag('#{tag.name}','#{obj.class.name.tableize.singularize}tag_list')) res << link_to(tag.name, link) end return res.join(" ") end
b) include tags.js
//modified selections from http://del.icio.us/ui/static/post.js?v=3o3
tag_delimitor = " "
function swap_tag(tag,elem) { swap_tag(tag,elem,true) } function swaptag(tag,elem,changecase){ if (change_case == true) { tag = trim(tag).toLowerCase(); } else { tag = trim(tag) } tags = document.getElementById(elem) var tagArray = trim(tags.value).split(tag_delimitor) var present = false; if (trim(tagArray[0]) == '') tagArray.splice(0,1); for (t=0; t<tagArray.length; t++) { if (trim(tagArray[t]).toLowerCase() == tag || (change_case == false && trim(tagArray[t]) == tag) ) { tagArray.splice(t,1); present=true; t-=1;
} } if (!present) { tagArray.push(tag); } var content = tagArray.join(tag_delimitor) //tags.value = (content.length > 1) ? content + ', ' : content tags.value = content; //focusTo(tags) }
function trim(str) { return str.replace(/^\s|\s$/g,""); }
c) Call from your form like
4) Also added a simple "spaced tag" helper to ActsAsTaggableHelper to put tags in blog footers (or whatever)
def spaced_tags(obj) res = [] obj.tags.each do |tag| res << link_to_tag(tag) end return res.join(" ") end
I would like to search Items by tags,
So I created a TagsController,
so that on a request like /tags/23 from the tag cloud, I can create a show method in TagsController that can do the findtaggedwith and return the Items.
How do I make this happen? As such, I cannot call findtaggedwith from the TagsController.
TIA
How does one display a tagcloud for the currentuser?
Thanks Sat
I think script/plugin install --force would certainly get you the newest version. You shouldn't need to run db:migrate again if you ran it before. Theoretically the user specific stuff was all there before in the database, just some of the functions weren't working quite right for it. After script/plugin you should be good to go, feel free to email me if it gives you problems and I will get the fixed up as soon as I can. Thanks for using the plugin, hope it is helpful.
I see that there is a new version that can handle user specific tags. How do I upgrade? Run script/plugin install --force? Is there any need to run db:migrate again when upgrading?
TIA for your help
@Sat:
Make sure that your controller is called "Tags" and not "Tag" and that you have
(not map.resource) in routes.rb.
I haven't provided an easy option for switching the token delimiter at this point I'm afraid. It should be pretty easy to switch. The portion in question is in actsas_taggableredux/lib/tags.rb in the parse function.
To prevent commas being replaced by spaces, comment out: list.gsub!(/,/, " ")
Then change the split around whitespace: tag_names.concat(list.split(/\s/))
To a split around commas: tag_names.concat(list.split(/,/))
And you should be set. I may have to add more explicit options for this kind of thing in the future.
It looks like it parses the tags by spaces versus commas, is there a way to switch that behavior so that it looks at the commas and groups words together?
I would say the issue is probably in your ItemsController, I'd need to see the code for that. Feel free to send me an email and I can probably help sort you out.
Thanks Thurin, that worked for me too.
Is there a way to filter the tag cloud for the current user? I am using acts_as_authenticated, so I can identify the current user any time.
Thanks in advance for all the help
I suppose you wouldn't have to have a tags controller, but the helpers are written with that assumption. (Thanks for pointing it out, I'll add it to the README).
I have it working with Rails 1.2.3 using:
map.resources :tags
in my routes.rb. The only issue i see is that when clicking a tag either from the cloud of from the tag list on an item i get the following error:
"uninitialized constant TagsController"
I assume I need to write a TagsController to handle looking for items that match the tag?
That means RESTful routes aren't getting setup properly. You will need EDGE rails, and a proper routes.rb
For edge, the easy way: rake rails:freeze:edge Or you can use svn/externals (google for 'edge rails svn')
Then make sure your routes.rb includes: map.resource :tags
Could you provide the whole error message? Feel free to post it or email it to me and I will see what I can do.
I found this plugin to be much better than actsas_taggable and actsastaggableon_steroids. It also has the DB optmization of yet another plugin out there included.
Monki, thanks for putting this out there. I just had one glitch, the tag_cloud method is not working in my view. It gives me a method not found error.
Can you point out what is wrong? BTW I am a RoR noob.
Thanks Sat