Agile Web Development

Build it. Launch it. Love it.

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.

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, #tag_list and #tag_list=. 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 ActiveRecord::Acts::Taggable::InstanceMethods 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 Post class, we can get a calculation of all the tag counts by using Post.tag_counts. 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

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 cached_tag_list 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 tags or taggings associations. To update the cached tag list you should call save_cached_tag_list 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 = " "

Other

Problems, comments, and suggestions all welcome. jonathan.viney@gmail.com

*Code King Rules.*

Vitals

Repository git://github.com/jviney/acts_as_taggable_on_steroids.git
License Rails' (MIT)
Rating (316 votes)
Owner Jonathan Viney
Created 27 November 2006

Comments

  • Avatar
    Abon
    19 December 2006

    Hi, I tried the plugin. I'm sure a add the line actsastaggable in the model I would like to tag. But I got a method missing error when I'm testing tag_with(). Any idea what I missed.

    THX

  • Michael Sheakoski
    3 January 2007

    You are confusing this with DHH's plugin. The proper way to add tags with this plugin is:

    @foo.tag_list = "mytag, two words, red"

  • Andy
    16 January 2007

    I recommend that if you call this "acts as taggable on steroids" you simply improve upon the functionality of actsastaggable (hence, putting it on steroids), rather than creating an entirely different plugin.

  • Avatar
    Thomas
    17 January 2007

    This plugin is cool. The only thing missing is the database structure (you have to google to find it).

    But, I even got pagination working, with tag searching

    page = (params[:page] ||= 1).to_i itemsperpage = 10 offset = (page - 1) * itemsperpage

    @document_count=Tag.find(:first, :conditions=>["name = ?",@params[:tag]]).taggings.count

    @documentpages = Paginator.new(self,@documentcount, itemsperpage, page) @documents=Document.findtaggedwith(@params[:tag], :limit=>itemsperpage, :offset=>offset,:order=>'created_at DESC')

  • Avatar
    23 January 2007

    The svn server for this plugin has been down for a while now, and I can't find any way to contact the plugins owner because his site has gone like the repository.

  • Avatar
    Jonathan Viney
    4 October 2007

    Yuval,

    You can use optionsforfindtaggedwith to generate the find options, and then use those with pagination.

  • Michael Sheakoski
    26 January 2007

    Jamie, it appears to be back up. In case you need to contact him in the future though the email is: jonathan .dot. viney @at@ gmail .dot. com

  • 29 January 2007

    Since folks have commented on the lack of database schema, however no one has taken a second to post it for others after eventually finding it, I thought this would be a good chance for me to get some karma credit..

    http://www.dotrb.com/articles/2007/01/28/actsastaggableonsteroids-database-schema

  • Jason
    1 February 2007

    It appears that my URL below got a little tweaked due to the formatting that this blog uses.. Didn't think to try code blocks on it. Anyhow, if you look at the URL you can see where it is missing the "_" characters in the acts as taggable on steriods URL.. Or, I guess you could just to go to the site and search for it.

  • 11 February 2007

    Sorry, stupid question here, but I just came across AaToS and I'm having trouble getting from where this posts leaves off to a tag cloud. Do I still need to define a "tag cloud" method as in the basic AaT?

  • 11 February 2007

    Actually, I think I've figured it out now that I took the time to look at what the method was returning in the source :). Thanks for the write up.

  • Avatar
    Aditya Raj
    1 March 2007

    This plug in is really very nice but the only thing that I dint like is that you cannot have any separator other than ',' and I wanted to separate the tags with space.

    I am new to ruby on rails but one thing I really like about it is convention over configuration, but it seems to be missing here.

    I hope you will modify this plug in soon..

  • Avatar
    David Madden
    3 March 2007

    It would be cool if it could remove duplicate tags on an object e.g. if a user entered "fish, chips, peas, peas" only 1 peas tag would be recorded for that object.

  • Sergei Barbarash
    7 March 2007

    The SQL in findtaggedwith does not work with eager finds because of table name conflict in the constructed query. For example - Model.findtaggedwith(tag, :include => :tags) fails with a SQL error.

    This is easily fixed by specifying aliases for the tables in SQL ("LEFT OUTER JOIN taggings tt ...").

  • Avatar
    22 March 2007

    For those looking for the schema to use to store the tags, you can use the schema defined in vendor/plugins/actsastaggableonsteroids/test/schema.rb after installing the plugin.

    Actually you will only need the first two tables. Add it to a migration and you are done.

  • Avatar
    Fred
    10 March 2007

    there is a minor bug, I tried to fix, but my little Ruby knowledge won't let... the bug is that when you put repeated tags when creating a new taggable model object, they all get added to the database, so a user could type the same tag 20 times and that tag will be top list in the tag cloud.

    how to fix it? anyone got a sugestion?

    tag = tag.uniq didn't work

  • Avatar
    Matt Barnicle
    16 March 2007

    Hi there.. Great plugin, very useful. I'm using it in a project now. I'm finding one part of it to be a little hard to use though. Whenever I want to get or set the tags, like to display to the front end or to set the tag list from an input box, I have to do a lot of prep on the data to get it to work in the CSV style for io. Wouldn't it be a whole lot easier if the interface to get and set tags were an array instead of a pseudo CSV string? I think I'm going to change the code to do that for us, but I wanted to suggest it to be part of the main distribution..

    Any way it goes, thanks for writing and releasing this!

  • jvp
    26 March 2007

    First off, great plug-in. Glad to see a new choice for tagging. I'm starting to use it now on one of my sites and it's working great.

    However, I agree with Matt. Marshalling and unmarshalling into and out of csv is cumbersome. I would prefer to deal with the tags as arrays and then front-end filter/present them as best works for my sites.

    I also wish it was easily configurable for the Tag.parse method whether to split on spaces or commas, whether to allow quoted strings, etc. I have modified the code for my purposes, but now I'll have to manually merge plug-in updates.

    Still, great plug-in and really glad you made it available!

  • Matthew Lang
    28 March 2007

    I've just finished implementing it on my first Rails project and it works like a charm.

    My only gripe though is that the tags are csv. It would be good to see this plugin with space delimited tags.

    Thanks for making this plugin available!

  • Avatar
    Jonathan Viney
    30 March 2007

    Plugin changes:

    • Tag.delimiter to set the delimiter
    • findtaggedwith and :include => :tags has been fixed
  • Shaun Doyle
    3 April 2007

    Nice plugin. I have just downloaded and got it up and running. I have just changed the tag delimeter to be a space (Tag.delimeter=" ").

    This saves the tags correctly. However when you read them back again with tag_list they are comma separated again.

    eg article.tag_list = "Ruby Rails" => "Ruby Rails" article.save => true article.tag_list => "Rails, Ruby" article.taglist = article.taglist => "Rails, Ruby" article.save => true article.tag_list => "Ruby, \"Rails,\""

    the read_tags method seems to still have comma functionality hardcoded into it. I think it should be looking at the new definition in Tag

    def read_tags tags.collect do |tag| tag.name.include?(Tag.delimiter) ? "\"#{tag.name}\"" : tag.name end.join(Tag.delimiter) end

  • Avatar
    dor kalev
    3 April 2007

    i just added these two methods: module InstanceMethods def untag(tag_name) taglist = self.taglist.split(', ') taglist.delete(tagname.include?(',') ? "\"#{tagname}\"" : tagname) @taglist = taglist.join(', ') end def tag(tag_name) @taglist = "#{self.taglist}, #{tagname.include?(',') ? "\"#{tagname}\"" : tag_name}" end end

    they make life much easier - using the tag_name for tagging/untagging.

  • Avatar
    16 April 2007

    Why would i get this when doing Photoset.tag_counts. Shouldn't hot have one entry and a count of "2" instead of "1"?

    • !ruby/object:Tag attributes: name: hot id: "1" count: "1"
    • !ruby/object:Tag attributes: name: sexy id: "2" count: "1"
    • !ruby/object:Tag attributes: name: hot id: "3" count: "1"
  • Avatar
    16 April 2007

    the following:<code> def testphotosetshouldhavetag_counts @photoset.tag_list = "crazy, lady, crazy" @photoset.save assert Photoset.tag_counts y Photoset.tag_counts end </code> Gives me:

    <code>

    • !ruby/object:Tag attributes: name: crazy id: "4" count: "1"
    • !ruby/object:Tag attributes: name: lady id: "5" count: "1" . </code> The sql needs some help. This is what you need... Get rid of the Group by tags.id part... So you have.. <code> SELECT tags.id, tags.name, COUNT() AS count FROM tags LEFT OUTER JOIN taggings ON tags.id = taggings.tag_id LEFT OUTER JOIN photosets ON photosets.id = taggings.taggable_id WHERE (taggings.taggable_type = 'Photoset') GROUP BY tags.name having count() > 0 ; </code>
  • Avatar
    16 April 2007

    The code change needed is as follows (hopefully someone can check this in.. hint: hint: ::) <code> vendor/plugins/actsastaggableonsteroids/lib/actsastaggable.rb 74c74

    < group_by = 'tags.id, tags.name having count(*) > 0'

    > group_by = ' tags.name having count(*) > 0' </code>

  • Avatar
    mcarr
    19 April 2007

    I've created a scalable version of this plugin. It keeps track of count in a variable instead of repeating db column entries. Also it brings back the add_tag feature from DHH. check it out at http://rubyforge.org/projects/scalabletagging/

  • Avatar
    Jonathan Viney
    25 July 2007

    Plugin changes:

    • Respect custom table names for the Tag and Tagging classes.

    • Fix the :exclude option for findtaggedwith

  • Avatar
    Jonathan Viney
    23 April 2007

    Plugin changes:

    • Fix tag_list to respect specific Tag.delimiter
  • Avatar
    26 April 2007

    Is it possible to count tags related to another tag with this plugin as it is? That is, find objects tagged with something, and then count those objects other tags and construct a tag cloud from that.

    I thought something like Foo.findtaggedwith('tag').tag_counts would do it, but it doesn't work.

  • Avatar
    Vasil
    30 April 2007

    Please, help! When I use this plugin, and write

    actsastaggable

    after thew name of the instance the error "Illegal fuction call" occures. It can'y see the methods from the plugion. What should I do?

  • Avatar
    hari
    2 May 2007

    I am using this plugin and staring at the following error

    NameError in EntryController#new
    undefined local variable or method `acts_as_taggable' for Entry:Class

    Please provide some guidance.

    -Thanks

  • Avatar
    dominik
    6 May 2007

    hi! I also wanted to use this plugin, but it produces the same error as hari (2 may 2007) describes!

    Please provide some help to me/us!

    • Thanks
  • Avatar
    herval
    26 May 2007

    adding caching to the plugin: http://hervalicio.us/blog/2007/05/25/caching-things-with-actsastaggableonsteroids/

    great and handy piece of work, by the way :)

  • Avatar
    28 May 2007

    Hey,

    Make sure your tagging_type column is sufficiently long enough to contain your taggable object names!

    I had a class object named ChannelBlogEntry which was stored as ChannelBlog.

    This might save you 30/40 minutes.

  • Avatar
    Madhan
    2 June 2007

    Adding on the idea of herval, I made a simple change which was sufficient for us so that we dont touch db during the read usages of tags:

    In actsastaggable.rb

    Added the following to Module ClassMethods
    beforesave :savecaches

    Added the following method to module InstanceMethods def save_caches
    if defined?(@tag_list)
    self.tagscache = @taglist end
    end

    Added a column tags_cache in the table for the model where u need tags.

    Then whenever u need to do only a read, use tags_cache on the model.

  • Avatar
    4 June 2007

    This plugin is great, I wrote some french help on how to setup the plugin and build a tag cloud.

    <a href="http://www.stoneageblog.com/articles/2007/06/03/nuage-de-tag-avec-ruby-on-rails-actsastaggable/"> Nuage de tag avec Ruby On Rails</a>

  • Avatar
    6 June 2007

    As I can get the list an тегов for обекта in rhtml file? @message.tag_list returns ощибку, but in script/console this works well

  • Avatar
    Peer Allan
    11 June 2007

    It would be great if you could include the schema for the tables used by this plugin. It is getting more difficult to find information on the DHH plugin and its docs now that it appears to be deprecated and/or no longer maintained. Thanks.

  • Avatar
    Jonathan Viney
    13 June 2007

    Recent changes:

    • migration generator
    • add findoptionsfortaggedwith for use with custom finders
    • caching support for tag_list

    Enjoy! -Jonathan.

  • Avatar
    Scott Thorpe
    14 June 2007

    Just updated the new Rev. 246 and some tags are gone but some are not.

    Anyone else having these problems?

  • Avatar
    Jonathan Viney
    15 June 2007

    More changes:

    • Introduce TagList class.
    • Array based accessors: object.taglist.add and object.taglist.remove
    • Tag.delimiter becomes TagList.delimiter
    • Various improvements

    These changes were reasonably substantial so I'd appreciate it if a few people could test them out so we can get bugs ironed out quickly. Please email me directly with any findings.

  • Avatar
    Todd Lee
    20 June 2007

    Hi, when I try to do the "prepare database" step, I get some error like "Mysql::Error: Table *.tags' doesn't exist: SHOW FIELDS FROM tags"

    This looks like it happens when I start from scratch.(I never used actsastaggable plugin)

    When I comment out all rows in "init.rb", it works. Am I doing something wrong?

    And one minor thing.. when "script/generate actsastaggablemigration" is run, the generated migration file name has .rb twice(003actsastaggable_migration.rb.rb)

    I'm using windows xp/rails 1.2.3.

  • Avatar
    Jonahan Viney
    21 June 2007

    I've fixed the extra .rb on the file name.

    I'm not sure why your migration isn't working. Please email me with more information.

  • Avatar
    Dianna
    1 August 2007

    Can this be used on the User model? I want users to be able to tag themselves - as well as posts.

  • Avatar
    22 June 2007

    testtagcounts_* unit tests all fail on my machine. I believe this is PostgreSQL-specific; Postgres complains, "Exception: PGError: ERROR: column "count" does not exist". I am running PostgreSQL 8.2, rails 1.2.3, and the 2007-06-21 version of your plugin. I can send you the query SQL if need be.

    Potential fix: in actsastaggable.rb, replace "count" with "count(*)" in the two lines containing the :atleast and :atmost options. This eliminates the Postgres complaint and the tests subsequently pass.

    I am no SQL expert so this is worth further verification.

    Thanks for working on this plugin, it's good stuff.

  • Avatar
    Jonathan Viney
    23 June 2007

    I've changed the SQL. Oshoma, can you try it again with Postgres and email me with the results.

    Other plugin changes:

    • Add validation to Tag model.

    • findoptionsfortaggedwith should always return a hash.

    • findtaggedwith passing in no tags should return an empty array.

    • Improve compatibility with PostgreSQL.

    Thanks, -Jonathan.

  • Avatar
    david
    28 June 2007

    Is it possible to create two kinds of tags? For example, I would like to be able to tag an object with Description tags in one form field and then Misc. tags in another form field. All for the same class/object.

  • Joe
    29 June 2007

    Quick bug report, and hopefully a good fix - if a user has a tag list that looks like: "foo, bar" and changes the case of a tag, i.e. to "Foo, bar", the case-changed tag is dropped, so the resulting tag list would be "bar".

    From a code perspective, what's happening is this:

    In save_tags:

    • newtagnames contains the new tag, i.e. "Foo", as the strings don't match
    • old_tags contains the old tag: "foo", as that is not in the new tag list
    • In the findorcreatebyname when the tags are actually being created, no new tag is created, as "Foo" matches "foo"
    • The "foo" tagging is then deleted

    There are a few options to fix it. One is simply to reverse the delete and the add - first delete, then add.

    Another, and I'm not sure how the performance would compare - i'm not sure whether DB string matching is faster than Ruby string matching, would be to delete all tags then add all tags

  • Avatar
    Jonathan Viney
    30 June 2007

    Joe, I can't reproduce your problem. Can you email me a failing test case?

  • Avatar
    Jonathan Viney
    3 July 2007

    Plugin changes:

    • Fix incorrect tagging when the case of the tag list is changed
    • Fix deprecated Tag.delimiter accessor
  • Avatar
    5 July 2007

    Hello.

    I get the same problem as Todd Lee posted on 20 Jun 2007, could the cause be found? For me, I'm on Ubuntu Linux with Rails Edge.

    Thanks from Belgium!

  • Avatar
    Paul
    4 November 2007

    Jaime, something like this should get you somewhere near:

    Model.tag_counts :limit => 100, :order => 'count desc'

  • Avatar
    6 July 2007

    I have the same error as aurels and Todd Lee from 20 June 2007. The problem happens when you run rake migrate on a project using AATOS when you have a blank database. I have traced it to line 8 of tag.rb, which contains "delegate :delimiter, :delimeter=, :to => TagList"

    If you comment out that line, the migration will load. It has something to do with the model loading and looking for relationships before the tables are created.

    Thanks!

  • Avatar
    6 July 2007

    By the way, if you drop and recreate a blank (no tables) development database, you can recreate this error. I do this regularly, using a remigrate script that I created to ensure I have a fully working migration set.

  • Avatar
    10 July 2007

    When trying to user the plugin with one table I always get a "false" as response when I try to save the model, e.g. p= Product.find(:first) p.tag_list="Golf"
    p.save ==> false p.reload.tag_list => #<TagList:0x320094c @names=[]>

    The tables Tags and Taggings are empty after this experiment.

    Please help!

  • Avatar
    riff42
    11 July 2007

    I may be misusing this awesome tool, but when I tag an object with something and then another users tags it, my original tag is replaced by anything the second user adds. Any suggestions?

    Here is my code:

    product.tag_list = params[:tags]
    engine.save
    
  • Avatar
    15 July 2007

    Is there any way to get count information for a Tag? I do tag = Tag.findbyname("tagname"), but tag.count always returns 0.

    I'd like to do this most efficient way too (with caching if possible).

    Any ideas? Been at it all day Thanks!

  • Kip
    15 July 2007

    Dimitry, been working on this today myself. To get the counts by tag (ignoring any associations):

    tagcounts = TaggedModel.tagcounts() tag_counts.each {|x| p x.name, x.count}

    This gets you the count tags for tags associated with this model.

    There are other options you can give tag_counts - check the source code.

    Cheers, --Kip

  • Avatar
    Jonathan Viney
    17 July 2007

    Plugin changes:

    • Fix the migration on edge rails
  • 19 July 2007

    Can the tags be scoped to a user so that a user has their own tags and clouds? Can anyone give me an example of how you would do this?

  • Avatar
    RainChen
    19 July 2007

    you forgot the tablenameprefix config. I use it in my app.

  • Avatar
    RainChen
    19 July 2007

    I hack the file lib/actsastaggable.rb,replace the code as : { :select => "DISTINCT #{table_name}.*", :joins => "LEFT OUTER JOIN taggings #{tablename}taggings ON #{tablename}taggings.taggableid = #{tablename}.#{primarykey} AND #{tablename}taggings.taggabletype = '#{name}' " + "LEFT OUTER JOIN tags #{tablename}tags ON #{tablename}tags.id = #{tablename}taggings.tag_id", :conditions => conditions, :group => group }.update(options)

    to:

    hack by RainChen @ 2007-7-19 16:40

          taggings_table = Tagging::table_name
          tags_table = Tag::table_name
          { :select =&gt; &quot;DISTINCT #{table_name}.*&quot;,
            :joins =&gt; &quot;LEFT OUTER JOIN #{taggings_table} #{table_name}_taggings ON #{table_name}_taggings.taggable_id = #{table_name}.#{primary_key} AND #{table_name}_taggings.taggable_type = &#x27;#{name}&#x27; &quot; +
                      &quot;LEFT OUTER JOIN #{tags_table} #{table_name}_tags ON #{table_name}_tags.id = #{table_name}_taggings.tag_id&quot;,
            :conditions =&gt; conditions,
            :group      =&gt; group
          }.update(options)
    

    I saw there were some places like these needed bo be changed.Hope you could deal with these issue and update to the svn.

  • Yaron
    19 July 2007

    Thanks for a great plugin. As I was customizing your code, I ran across the :exclude option of the findoptionsfortaggedwith() function. My tests show that it doesn't work.

    I believe the problem is the logic of the following statement: conditions = sanitizesql(["#{tablename}_tags.name #{"NOT" if options.delete(:exclude)} IN (?)", tags])

    Think about it, simply adding a NOT won't do the job if a taggable item has more than one tag.

  • Avatar
    Rainchen
    20 July 2007

    anyone knows how to get it work with the plugin "will_paginate"?

  • Avatar
    Chris Cameron
    23 July 2007

    I asked this once, but I think it got lost in the shuffle, does anyone have any experience with using this in a per-user way. I want to integrate this with the restful_authentication plugin and have each tag scoped to a user. Thanks for any help!

  • Avatar
    dirx
    24 July 2007

    can someone please give me a hint to get it to work with activescaffold?

  • Joe
    25 July 2007

    I'm not sure if this functionality exists or doesn't, but it would be nice:

    Something like: TaggableType.find(whatever).tag_counts returns the union of all the tags found in that set.

    Or... something like: Tag.findrelatedtagcounts(taglist) Outputs the tag counts for all tags not in the list that are applied to all taggables tagged by the tags in the list

  • Joe
    26 July 2007

    Here's one of the things I suggested, though I haven't tested it entirely.

    Post.relatedtagcounts(tags) returns the tag counts for all posts tagged with tags, excluding the tags not in tags.

    def relatedtagcounts(tags) tags = if tags.is_a?(String) TagList.from(tags).names else tags.dup end

          conditions = [
            &quot;taggings.taggable_type = #{quote_value(name)}&quot;,
            &quot;#{table_name}_taggings.taggable_type = #{quote_value(name)}&quot;,
            sanitize_sql([&quot;source_tags.name IN (?)&quot;, tags]),
            sanitize_sql([&quot;tags.name NOT IN (?)&quot;, tags])
          ]
          conditions = conditions.compact.join(&#x27; AND &#x27;)
    
          Tag.find(:all,
            :select     =&gt; &#x27;tags.id, tags.name, COUNT(*) as count&#x27;,
            :joins      =&gt; &quot;LEFT OUTER JOIN taggings ON tags.id = taggings.tag_id &quot; +
                           &quot;LEFT OUTER JOIN taggings #{table_name}_taggings ON #{table_name}_taggings.taggable_id = taggings.taggable_id &quot; +
                           &quot;LEFT OUTER JOIN tags source_tags ON source_tags.id = #{table_name}_taggings.tag_id&quot;,
            :conditions =&gt; conditions,
            :group      =&gt; &#x27;tags.id, tags.name HAVING COUNT(*) &gt; 0&#x27;,
            :order      =&gt; &#x27;COUNT(*) DESC&#x27;
          )
        end
    
  • Avatar
    Jim Morris
    30 July 2007

    I have blogged about the method I use to paginate actsastaggable with will_paginate.

    http://blog.wolfman.com/articles/2007/07/30/paginating-actsastaggable-with-will_paginate

  • Avatar
    Randy
    6 August 2007

    A really nice feature would be to add caching functionality for objects with related tags. So instead of having to call findtaggedwith and run a huge query (especially if your DB is large and your objects have lots of common tags -- and also right now it's impossible to get random results without find every object first), it would already have the related object taggable_id's cached somewhere. I'd work on this myself but my ruby/sql-fu isn't strong enough yet.

  • Avatar
    7 August 2007

    I have a little problem. In my tag cloud, when I have a tag with a period(es: "web2.0"), and I send this param to Contoller, when I print this param in the controller, became "web2". Can you help me? Thanks

  • Michael
    15 August 2007

    Hi, great Plugin!

    I think it would be usefull to eliminate commas before adding a single tag via tag_list.add():

    tag_list.add(params[:tag][:name].gsub(/\,/, ' '))

  • Avatar
    senthil
    16 August 2007

    Hi Guys can anyone suggest a way to add two independant sets of tags for a model? thanks in advance

  • Avatar
    Ray Daly
    22 August 2007

    Having trouble with x.tag_list.remove(params[:untagme]) x.save and end up with an error

    Was successful in adding several a thousand tags with

      x.tag_list=x.keyword
      x.save
    

    So now sure where problem might be.

    Mysql::Error: Unknown column 'id' in 'where clause': DELETE FROM taggings WHERE id = NULL

  • Avatar
    Doug McBride
    22 August 2007

    I'm getting Todd's error also: "when I try to do the "prepare database" step, I get some error like "Mysql::Error: Table *.tags' doesn't exist: SHOW FIELDS FROM tags"

    Anyone know why? Seems like a bootstrapping bug in the plugin.

  • Avatar
    Jonathan Viney
    26 August 2007

    [26 August 2006]

    • Remove deprecated Tag.delimiter. Use TagList.delimiter instead.

    [25 August 2007]

    • Make tagcounts work with hasmany :through

    [23 August 2007]

    • Make search comparisons case-insensitive across different databases. [Moisés Machado]

    • Improve compatiblity with STI. [Moisés Machado]

  • Avatar
    Bryce Hammond
    26 August 2007

    Great update Jonathan. I noticed one thing that doesn't quite work right anymore. If you pass a :conditions option to findtaggedwith the WHERE clause logic doesn't work correctly because the tag matching conditions are not encapsulated (so the ORs override anything you put in the conditions). I fixed this quickly by changing

    conditions << tags.map { |t| sanitizesql(["#{tagsalias}.name LIKE ?", t]) }.join(" OR ")

    to

    conditions << "( " + tags.map { |t| sanitizesql(["#{tagsalias}.name LIKE ?", t]) }.join(" OR ") + " )"

    in actsastaggable.rb.

  • Jonathan Viney
    29 August 2007

    Bryce, please send through a failing test case. jonathan.viney@gmail.com

  • Yuval
    30 August 2007

    Hey guys, this may come across as a newb question. That's because I'm a newb. Anyway, I've saved a class by setting its taglist and can successfully search on tags and retrieve an object's tags. However, what I want to do is parse those tags and apply a specific format/url to each of them. It appears that object.taglist is a string. Do I need to do my own splitting and parsing or is there a way of getting back the tag list as an array? Cheers.

  • Avatar
    Yuval
    30 August 2007

    Further to my last comment, I've ended up just using object.tags rather than object.tag_list, as it seems to return a proper collection. Is this bad form with regards to this plugin? Does it bypass the caching? Cheers.

  • John N.
    31 August 2007

    I have found some behavior I believe to be inconsistent. Consider the following two test cases:

    def testdoubletag_passes p = Post.create(:text => "Test", :tag_list => "one, one, two") p.save

    assert_equal [p], Post.find_tagged_with([&quot;one&quot;, &quot;two&quot;],:match_all =&gt; true)
    

    end

    def testdoubletag_fails p = Post.create(:text => "Test") p.save p.tag_names = "one, one, two"

    assert_equal [p], Post.find_tagged_with([&quot;one&quot;, &quot;two&quot;],:match_all =&gt; true)
    

    end

    Seems like the should both pass.

  • Avatar
    Jonathan Viney
    1 September 2007

    John N:

    The second example you give has two problems. First, the accessor is called taglist not tagnames. Secondly, you need to save the post after setting the tag_list.

  • Avatar
    Jonathan Viney
    1 September 2007

    Yuval:

    If you directly modify the taggings or tags associations you need to take care of the caching yourself by calling savecachedtaglist. The taglist accessor is designed to be used by a text input on a form.

  • Yuval
    3 September 2007

    Thanks Jonathan, that makes more sense now: use tag_list when saving tags, but directly referce object.tags when displaying/parsing tags. Cheers.

  • 5 September 2007

    Please adjust you documentation. It should be

    TagList.delimiter = " "

    instead of

    Tag.delimiter = " "

  • ocher
    11 September 2007

    Yuval, i think that you should use object.tag_list.names to get array of object's tags. I've been also searching today for this method and found that one. It works, but in my opinion TagList class inherit Array class and implement Enumerable. Then instead of "names" we could simply run "each" method.

  • Avatar
    Jonathan Viney
    12 September 2007

    [12 September 2007]

    • Make the TagList class inherit from Array.

      BACKWARDS INCOMPATIBILITY:

      TagList#initialize, TagList#add, and TagList#remove no longer accept array arguments.

      Old: TagList.new(["One", "Two"]) New: TagList.new("One", "Two")

    • Deprecate obsolete TagList#names.

  • Avatar
    Jonathan Viney
    16 September 2007

    [17 September 2007]

    • Fix clearing of cached tag list when all tags removed.
  • Avatar
    Guillaume Dufloux
    26 September 2007

    Hi, it's about Tag cloud calculations.

    I needed to only show tags from ONE post, but with GLOBAL tags calculation (to show how much tags of a given post are popular)

    Example : "tag1"(post 1,2,3)=3 "tag2"(post 1,2)=2 "tag3"(post 2)=2. I would like global counts for tags of (post 1), so "tag1"(3) and "tag2"(2).

    Obviously, Post.tag_counts(:conditions => "taggings.taggable_id=#{@post_1.id}") return "tag1"(1) and "tag2"(1) (ok, each tag is uniq for a given post)

    So, there's maybe (not) a good SQL query for that, but I decided to use Post.tag_counts result, and then 'filter' via ruby condition ( self.tag_list.include? tag[:name]) on collect.

    I put it as an InstanceMethods in Taggable module. Then you can ask : @post.global_tag_counts

    Here's the code : http://pastie.caboo.se/100963

    And here's a Tagshelper : http://pastie.caboo.se/100968

    I think it becomes slow with many tags, but I didn't observe any counter-perf up to 1000 tags. Ruby's not so slow ;)

    Regards,

  • Avatar
    Guillaume Dufloux
    26 September 2007

    RE: global_tag_counts

    Just to put you in the user context : observe tags that are related to this article. Don't you think that it should be great to know which of these are most used ? (ok, there's a lot of them are used for evil...)

    @jonathan : could you add a tags_helper.rb generator, principally for cloud helper that are wide used.

    Thanks for all ;)

  • Avatar
    26 September 2007

    :matchall doesn't seem to work for me. The query it generates doesn't work against Postgres 8.2. Basically, I have a model called NewsRelease, which has "actsastaggable". Using NewsRelease.findtagged_with("test test2") generates the following query:

    SELECT DISTINCT newsreleases.* FROM newsreleases LEFT OUTER JOIN taggings newsreleasestaggings ON newsreleasestaggings.taggableid = newsreleases.id AND newsreleasestaggings.taggabletype = 'NewsRelease' LEFT OUTER JOIN tags newsreleasestags ON newsreleasestags.id = newsreleasestaggings.tagid WHERE (newsreleasestags.name LIKE 'test' OR newsreleasestags.name LIKE 'test2') GROUP BY newsreleasestaggings.taggableid HAVING COUNT(newsreleasestaggings.taggableid) = 1

    Unfortunately, Postgres doesn't like that syntax. Specifically, it says:

    ERROR: column "news_releases.id" must appear in the GROUP BY clause or be used in an aggregate function

    Any thoughts?

  • Avatar
    26 September 2007

    Okay, I figured out my problem with match_all. Under Postgres, if you use a GROUP BY clause, all returned columns must either be in the GROUP BY or be in aggregate functions. From the docs:

    When GROUP BY is present, it is not valid for the SELECT list expressions to refer to ungrouped columns except within aggregate functions, since there would be more than one possible value to return for an ungrouped column.

    The solution is a small fix to actsastaggable.rb. Around line 62. Rearrange the block that generates the GROUP BY clause such that it adds all of the table's columns.

    if options.delete(:match_all) group = "#{taggingsalias}.taggableid" column_names.each do |colname| group += ", #{table_name}.#{colname}" end group += " HAVING COUNT(#{taggingsalias}.taggableid) = #{tags.size}" end

    http://bealetech.com/articles/2007/09/26/actsastaggableonsteroids-match_all-and-postgres

  • Avatar
    Jonathan Viney
    27 September 2007

    [27 September 2007]

    • Add #tag_counts method to get tag counts for a specific object's tags.
  • Avatar
    Jonathan Viney
    28 September 2007

    [29 September 2007]

    • Add TagsHelper to assist with generating tag clouds and provide a simple example.
  • Avatar
    beltrachi
    30 September 2007

    There is a little error on the tag_cloud view:

    <% tagcloud @tags, %w(css1 css2 css3 css4) do |tag, cssclass| %> <%= linkto tag.name, { :action => :tag, :id => '''tag.'''name }, :class => cssclass %> <% end %>

    Anyway, congratultations for this plugin!

  • Avatar
    Yuval
    1 October 2007

    I continue to have problems with this plugin, particularly after the last update, and sparse documentation has me scratching my head. Does anyone by chance have a fully operational and documented implementation online anywhere for code references?

    Specifically, I need to do the following:

    Get a formatted list of an object's tags. I am using object.tags.map {|tag| "#{taglink(tag)}"}.join(" | ") where taglink is a helper that returns a formatted search link for the tag. This works fine, but I'm not sure if it's correct.

    Delete a specific tag for an object. Using a similar map as above, I am generating delete links that pass in the ID of the object and the id of the tag, then in the controller doing: Object.find(params[:objectid]).taggings.findbytagid(params[:tag_id]).destroy. As above, this works fine, but seems too verbose.

    Where I am having problems is in adding new tags for an object that has pre-existing tags. Before the latest revisions, I was doing Object.find(params[:id]).tag_list.add(TagList.parse(params[:whatever])) but this no longer seems to work, and instead adds everything I enter as a single tag, even though they're seperated by commas.

    Any help appreciated.

  • Avatar
    Jonathan Viney
    2 October 2007

    [2 October 2007]

    • Add :parse option to TagList#new and TagList#add.

      tag_list = TagList.new("One, Two", :parse => true) # ["One", "Two"]

      tag_list # ["One", "Two"] tag_list.add("Three, Four", :parse => true) # ["One", "Two", "Three", "Four"]

    • Remove TagList#names.

  • Avatar
    Jonathan Viney
    2 October 2007

    Yuval,

    Your method for constructing a list of tags is fine. You could use tag_list instead of tags to take advantage of caching if you are using it.

    To remove a tagging, you could pass in the tag name rather than the id, and then use tag_list.remove

    object = Object.find(params[:id]) object.tag_list.remove(params[:tag]) object.save

    The API for TagList#add has been changed. The changelog has the details. I also justed added a shortcut for parsing a tag list that you want to add.

    object.tag_list.add(params[:whatever], :parse => true)

    Cheers, -Jonathan.

  • Avatar
    Jonathan Viney
    2 October 2007

    Thanks beltrachi, I've corrected the readme.

  • YUval
    2 October 2007

    Thanks Jonathan! I'll try out the latest rev. My concern with the remove method is that it depends on a tag name, which could be any combination of querystring-destroying values. I'd rather use the ID, hence my going directly to an object's taggings.

  • Yuval
    2 October 2007

    P.S. New parse option works great. Cheers.

  • Avatar
    2 October 2007

    There is a little mistake on the tag_cloud example. On this line:

    <%= linkto tag.name, { :action => :tag, :id => name }, :class => cssclass %>

    It should be:

    <%= linkto tag.name, { :action => :tag, :id => tag.name }, :class => cssclass %>

    That is :id => tag.name (not just "name")

  • Yuval
    2 October 2007

    The tag cloud helper wasn't working for me, producing one tag with a maximum index while everything else was stuck at min. I used the existing tag_counts property but used the tag cloud helper found here http://www.juixe.com/techknow/index.php/2006/07/15/acts-as-taggable-tag-cloud/ and it seems to work as expected. I may have missed something.

  • Avatar
    Yuval
    3 October 2007

    Another request :) extend findtaggedwith with pagination, so you can make a single call that returns a paginator and result set for the current page, using the submitted options.

  • Avatar
    Christian
    6 October 2007

    Thanks for this great plug-in. However I have problems deleting tags. Using object.tag_list.remove(params[:tag]), only removes the row from the tagging table but not from the tag table. Any ideas???

  • Avatar
    Jonathan Viney
    7 October 2007

    Christian,

    That's the behaviour I needed for a project a hile back. I don't mind adding an option to remove unused tags though. Send through a patch if you like.

  • Avatar
    Martin Gamsjaeger
    14 October 2007

    First of all, thx for the nice plugin! However, I just tried to get it to work with latest rails (rev >= 7873) and it seems as if the call to 'findorcreatewithlikebyname' @line 158 in actsastaggable.rb doesn't work anymore? (I'm getting undefined method error). I changed it to 'findorcreatebyname' and it works now (obviously without the 'like' sql stuff, if that's what it was meant for :)

    Any ideas?

  • Avatar
    14 October 2007

    Hi, i found a bug when using :conditions and finding by multiple tags. The plugin creates SQL like "condition AND firsttagcontition OR secondtagcondition" which should be "condition AND (firsttagcontition OR secondtagcondition)".

    I also extended my copy of this plugin a bit because my language is not safe-chars which i coul use in uri so i quickly set up an attribute called stringid a modified it so i can select tags by their stringids (which are safe chars usable in url). Ordinary languages are not safe chars so you may consider this a feature request.

    Good work guys, keep it up!

  • Avatar
    Jonathan Viney
    15 October 2007

    Thanks Michal, I've applied a fix.

  • Avatar
    Jonathan Viney
    15 October 2007

    [15 October 2007]

    • Make findtaggedwith correctly apply :conditions

    • Add Tag.destroy_unused option.

  • josh
    19 October 2007

    Great plugin! I just noticed that if you use eager loading with :match_all that it doesn't return the tag intersection like it would if you leave off eager loading...

    Resource.findtaggedwith(tags, :match_all => true) # works

    Resource.findtaggedwith(tags, :include => [:tags], :match_all => true) # doesn't work

  • Avatar
    Jonathan Viney
    21 October 2007

    [22 October 2007]

    • Fix findtaggedwith using :match_all and :include.
  • Avatar
    Yuval
    23 October 2007

    Any suggestions for getting a tagcount based off of, for instance, posts made by multiple users? I find that if I do something like category.posts.tagcounts, it works great. But if I do something like Post.find(:all, :conditions => whatever) or get a collection of posts via a sql query, I get an exception, "undefined method tag_counts for Array". Thanks!

  • Avatar
    Mario
    24 October 2007

    Hi Jonathan,

    Fantastic work my friend. I'm a newbie and STILL able to get a functional tagging system up and working. Thank you so much.

    I was wondering if you had any idea about an error i see when trying to generate a tag cloud.

    I copy/pasted the code you provided above and still get the following error:

    NoMethodError in Posts#tag_cloud

    undefined method `tag_cloud' for #<#<Class:0x4883bec>:0x4883bc4>

    The bad line:

    4: <% tag_cloud @tags, %w(css1 css2 css3 css4) do |tag, css_class| %>

    i have included the helper in application_helper.rb... any ideas whats up?

    Again, thank you so much.

  • Avatar
    3 November 2007

    Hi, I have an application with more than 100.000 tags (a web spider), and I would like to show a tag cloud, but the method explained above will generate a cloud for all the tags (Model.tag_counts), and that wouldn't work for me as I have so many tags.

    So, how can I limit the number of tags on the tag cloud? I would like to show, say, the 100 most popular tags. Or maybe paginate the tag cloud, ordered by popularity or any other atribute?

    Thanks

  • Avatar
    Jason Galvin
    21 November 2007

    Mario, make sure you have the line 'include TagsHelper' in your applicationhelper.rb file *and* make sure that you don't have a helper file named tagshelper.rb in your helpers directory, which would interfere with the TagsHelper from the plugin.

  • gc
    29 November 2007

    <p>How in the world do you add on to existing tags using a form? My solution works, but I feel like it's not ideal.</p> <p>So my actsastaggable model is a Place. In the form, I have something like this:</p> <code> <%= textfield("place", "taglist") %> </code>

    <p>Then in the create method I have:</p> <code>

    we just need a temp place object to grab the tag_list the user entered

    <br> @temp_place = Place.new(params[:place]) <br>

    find the existing place

    <br> @place = Place.find(some id I use to find it) <br>

    add on to its tag_list with the new tag list the user entered

    <br> @place.taglist.add(@tempplace.tag_list) <br>

    save the place, thus updating the tag_list

    </code> <p>The Place model isn't my primary model in the form, hopefully that explains why I did some things like I did. Can anyone suggest a different way of adding on to the tag_list? Thanks!</p>

  • Yuval
    4 December 2007

    Thought of a feature request in the course of using this plugin. It would be nice if taggings had an additional association attribute, like user_id, so that the ownership of tags can be determined. That way, tag deletion could be limited to the tag author.

  • stoney
    10 December 2007

    With Rails 2.0.1, this plugin fails testtagdestroyedwhenunused in actsastaggable_test.rb. I don't see why this would be. Any advice?

  • Avatar
    bart
    17 December 2007

    working from example below, I added this to actsastaggable to find related tags. Not fully tested so use with caution. I modeled it closely after tag_counts <code> # Calculate the tag counts for all related tags. def relatedtagcounts(tags, options = {}) tags = TagList.from(tags) if tags.is_a?(String)
    Tag.find(:all, findoptionsforrelatedtag_counts(tags, options)) end

        def find_options_for_related_tag_counts(tags, options = {})
          options.assert_valid_keys :start_at, :end_at, :conditions, :at_least, :at_most, :order, :limit
          options = options.dup
    
          scope = scope(:find)
          start_at = sanitize_sql([&quot;#{Tagging.table_name}.created_at &gt;= ?&quot;, options.delete(:start_at)]) if options[:start_at]
          end_at = sanitize_sql([&quot;#{Tagging.table_name}.created_at &lt;= ?&quot;, options.delete(:end_at)]) if options[:end_at]
    
          conditions = [
            &quot;#{Tagging.table_name}.taggable_type = #{quote_value(base_class.name)}&quot;,
                        &quot;taggings2.taggable_type = #{quote_value(base_class.name)}&quot;,
                        sanitize_sql([&quot;source_tags.name IN (?)&quot;, tags]),
                        sanitize_sql([&quot;#{Tag.table_name}.name NOT IN (?)&quot;, tags]),        
            options.delete(:conditions),
            scope &amp;&amp; scope[:conditions],
            start_at,
            end_at
          ]
    
          conditions &lt;&lt; type_condition unless descends_from_active_record? 
          conditions.compact!
          conditions = conditions.join(&#x27; AND &#x27;)
    
          joins = [&quot;INNER JOIN #{Tagging.table_name} ON #{Tag.table_name}.id = #{Tagging.table_name}.tag_id&quot;]
                    joins &lt;&lt; &quot;INNER JOIN #{Tagging.table_name} taggings2 ON #{Tagging.table_name}.taggable_id = taggings2.taggable_id&quot;
                    joins &lt;&lt; &quot;INNER JOIN #{Tag.table_name} source_tags ON source_tags.id = taggings2.tag_id&quot;
                    joins &lt;&lt; &quot;INNER JOIN #{table_name} ON #{table_name}.#{primary_key} = #{Tagging.table_name}.taggable_id&quot;
                    joins &lt;&lt; scope[:joins] if scope &amp;&amp; scope[:joins]
    
                    at_least  = sanitize_sql([&#x27;COUNT(*) &gt;= ?&#x27;, options.delete(:at_least)]) if options[:at_least]
                    at_most   = sanitize_sql([&#x27;COUNT(*) &lt;= ?&#x27;, options.delete(:at_most)]) if options[:at_most]
                    having    = [at_least, at_most].compact.join(&#x27; AND &#x27;)
                    group_by  = &quot;#{Tag.table_name}.id, #{Tag.table_name}.name HAVING COUNT(*) &gt; 0&quot;
                    group_by &lt;&lt; &quot; AND #{having}&quot; unless having.blank?
    
                    { :select     =&gt; &quot;#{Tag.table_name}.id, #{Tag.table_name}.name, COUNT(*) AS count&quot;, 
                        :joins      =&gt; joins.join(&quot; &quot;),
                        :conditions =&gt; conditions,
                        :group      =&gt; group_by
                    }.reverse_merge!(options)
                end
                ## luu &gt;
    

    </code.

  • Avatar
    20 December 2007

    Stoney, I found that that test will pass if you add this line to savetags in actsas_taggable.rb at line 175.

    <pre> oldtags.each{|tag| tag.destroy} if Tag.destroyunused </pre>

    See this post:

    <a href="http://blog.s21g.com/genki?tag=bug">http://blog.s21g.com/genki?tag=bug</a>

  • Avatar
    21 December 2007

    using the tag cloud as mentioned in the view example will miss-up your tags.

    so instead of using: <pre>%w(css1 css2 css3 css4)</pre>

    use a hash: <pre>["css1", "css2", "css3", "css4"]</pre>

  • Geek
    26 December 2007
    1. it generates sql with syntax error (I fixed it myself)
    2. tag_cloud method doesn't work (I gave up)
  • Avatar
    Franz Woyzeck
    16 January 2008

    I think that the functionality is broken (at least under RoR 2.0.x). MyEntity.taglist always returns arrays of Strings and not arrays of Tags, so the count-method is not available on the TagList's items and tagcloud fails.

  • Avatar
    18 January 2008

    The plugin is good, thanks. But, I need a way to count and show the number of taggables assigned to each tag. Also, I want to know if you is working in updates for actsastaggable?

  • Avatar
    18 January 2008

    The plugin is good, thanks. But, I need a way to count and show the number of taggables assigned to each tag. Also, I want to know if you is working in updates for actsastaggable?

  • Avatar
    20 January 2008

    (rdb:5) @activity.save
    true
    (rdb:5) @activity.tag_list = tags
    ["Tempo libero"]
    (rdb:5) @activity.save
    NoMethodError Exception: undefined method `name' for "Tempo libero":String

    I think that the functionality is broken (at least under RoR 2.0.x)

  • Avatar
    21 January 2008

    This is a very useful plugin. I use it to classify very large amount of items.

    I often to find items that match some tags and donot match some other tags. does plugin support:

    foobar.findtaggedwith(:include => ["a","c"], :exclude => ["b"] (to find something mathcs "a,c" but "b") ???

    as far as i remeber, some previous version support foobar.findtaggedwith("a,c,!b") to find items was tagged with "a,c" but wasnot tagged with "b".

    Thank you for replies

  • Avatar
    kcruci
    23 January 2008

    undefined method `tag_list'

  • Avatar
    Nobrow
    28 January 2008

    Its easy enough to add yourself, but I think the find method should accept and merge :select and :joins options. Cant see any reason not to, and I very quickly found a reason to do.

  • Jonathan Viney
    30 January 2008

    Fix Tag.destroy_unused for Rails 2.0

  • Avatar
    Adam Wilson
    2 February 2008

    Migration not working!

    I installed actsastaggable and found this after looking for help on getting that working. Running migrate does not create any tables. I get no errors though.

    I'm using Rails 2.0

  • Avatar
    16 February 2008

    I'd like to get 5 results with the most tags in common with the current model. How should I go about doing this?

  • Patrick
    18 February 2008

    For the savecachedtaglist function in actsastaggable.rb. Just found that if remove the last tag for some model. The cachedtaglist will not be updated to empty string because the condition "and !taglist.blank?" will disallow the cachedtaglist to update

  • Avatar
    Juan Matías
    18 February 2008

    I have two models Region and Product:

    Region has_many :products Product belongs_to :region

    When I do this:

    @region.products.findtaggedwith("casa")

    I get:

    ActiveRecord::StatementInvalid: Mysql::Error: Unknown column 'productstags.name' in 'where clause': SELECT products.* FROM products INNER JOIN productsregions ON products.id = productsregions.productid WHERE ((productsregions.regionid = 1)) AND ((products_tags.name LIKE 'casa'))

    Can I use 'findtaggedwith' method trough associations?

  • Avatar
    Jeremy
    21 February 2008

    I get the impression that :match_all => true is pretty broken right now. For example...

    I have 200 or so records with the tag "tag1".

    Model.findtaggedwith('tag1') will return all 200, but Model.findtaggedwith('tag1', :matchall => true) returns a single row. Model.findtaggedwith('tag1,tag2', :matchall => true) should return no rows, but instead returns them all.

  • Avatar
    Jeremy
    21 February 2008

    Disregard my previous comment.. that behavior was being caused by the same entities being assigned the same tag multiple times in the taggings table... not sure how that happened.

    It might be prudent to change the count being done by matchall from COUNT(*) to something like COUNT(DISTINCT #{tablename}.id) to avoid problems like that...

  • Patrick
    27 February 2008

    Please ignore my post on 18 Feb 2008 for about savecachedtag_list. I found that it is fixed in the latest version.

  • Avatar
    jc
    28 February 2008

    How would you go about validating individual tags? I find that I can't use validates_associated on my models because I don't have any associations declared. The way the tags and taggings models are built though it doesn't seem like there's an easy way to declare associations. Is there a way to declare them easily? Is there another way to validate each individual tag?

  • Avatar
    jc
    29 February 2008

    Right now when I try to add a validation to a tag (without trying to specify any extra associations than the ones already made by the plugin) and it fails to validate I get the following error:

    Cannot associate new records through 'Advice#taggings' on '#'. Both records must have an id in order to create the has_many :through record associating them.

    Advice is the model I'm using it on.

  • Avatar
    5 March 2008

    That is a great plugin Jonathan. To make an even greater use of it I need to make several models taggable. But now, is there a simple way to get combined tag counts for all of my models? Thanks

  • Avatar
    5 March 2008

    Another problem I found: In PostgreSQL 'LIKE' clause is case-sensitive :( 'ILIKE' is the case-insensitive version. It is not a big problem for me, as I can just do this little modification in the code but I just thought you might want to know that.

  • Avatar
    9 March 2008

    tags made of a phrase of two words, such as "rain hats", when used in a linkto where id is the tag, result in a broken link on rails 2.0.1 as the link has a space in it. Is this a problem with linkto url encoding? How are we to compensate for this?

  • Avatar
    Chris
    23 March 2008

    I'm new to Rails so I apologize if this is pretty basic.

    First, I'd like the thank you for an awesome plugin. It works flawlessly and has been very simple for me with one exception...

    How do I return the actual number of times a tag is used rather than the name of the tag? For instance:

    Url.tag_counts will return the tag names to be used in a tag cloud. I'd like to actually know that tag1 was used X amount of times and tag2 was used Y amount of times, etc.

    Any suggestions would be greatly appreciated.

  • Sebjørn
    27 March 2008

    Hi.

    Great plug-in, but I have a problem with setting the delimiter. I am a novice in the ruby/rails-world.

    I get the error "rake aborted! uninitialized constant TagList" when trying to do "rake db:migrate" when I add the line TagList.delimiter = " " to environment.rb. If I comment out the line, everything works fine.

    Do you have any idea? I am pretty sure it is something stupid that I just haven't understood ;)

  • Dan Webb
    27 March 2008

    OK, I know this is probably a fairly simple question but bear with me. I've added tags to 2 separate models (topics and posts) successfully from within the console. I'm just struggling to do it within the view context. Controller:

    1. def add_tags
    2. @topic = Topic.find(params[:id]) #@tag = 'another test' #@tag = Topic.tag_list.add(params(:tags))
    3. @topic.tag_list.add(:tags)
      @topic.save end

    View (show): <% formfor(:topic, :url => objecturl, :html => { :method => :put }) do |f| %> <p> <label for="topic_title">Add Tag</label> </p> <%= f.text_field :tags %>

    <%= submit_tag "add tag" %> <% end %>

    It's giving me the error "can't convert String into Array". So I'm guessing it's not actually using the tag_list.add method.

    Any suggestions :) Cheers, Dan

  • Jantzen
    28 March 2008

    This helped me out with creating and updating the tags in the view.

    I haven't figured out how to make them link_to yet though.

    http://www.rubyplus.org/episodes/26-SEO-for-Rails-app-using-Acts-as-Taggable-on-Steroids-and-Meta-Tags-Plugins.html

  • rupert
    1 April 2008

    [Juan] > Can I use 'findtaggedwith' method trough associations?

    I've just hit the same problem as you with through associations. This is NOT a problem with the plugin but is an issue with rails - see:

    http://dev.rubyonrails.org/ticket/6821

    this has been fixed in edge rails - version 9022 so you should find that all works fine if you switch to edge rails.

  • lunaclaire
    11 April 2008

    Hope this is cool to post here as it asks ?'s about the plugin AND rails polymorphism... Also kinda long

    I've been using the actsastaggableonsteroids plugin successfully for awhile with models descended directly from ActiveRecord, but just ran into something strange in a new use case where I have models that are subclasses of other models.

    I'm looking for an explanation and a workaround or correction to the way I'm doing things and it occurs to me that someone may have an answer if they have good knowledge about rails' polymorphic operation OR about the way actsastaggable works...

    Here's my problem -

    1) Models -

    class Group < ActiveRecord::Base

    class Circle < Group

    class SupportCircle < Circle

    2) I have Circle declared as actsastaggable

    3) when I tag a Circle, the 'taggings' table record for it has 'Group' for the 'taggable_type' column

    Q1: why isn't it 'Circle' for the 'taggable_type'? Q2: where in the code is this assignment of the value done? (I can't seem to find it and assume it's some "under the covers" magic that Rails is doing...?)

    4) actsastaggable.rb's 'findtaggedwith' method does the query with a join that has this fragment:

    AND #{tablename}taggings.taggable_type = '#{name}'

    So, when I do a search for Circle objs tagged with a tag, it fails to find those tagged objs because when I call Circle.findtaggedwith(tag), the 'name' is coming in as 'Circle' while the entry in the table is 'Group' as described above.

    Q3: why is the search value inconsistent with the 'tagging' insert's assignment of value for 'taggable_type'?

    5) I want to start tagging SupportCircle's and not sure of a few things...

    Q4: with an actsas declaration, do I need to explicitly declare that in a subclass or will SupportCircle be taggable because Circle is declared so? Q5: if I want to distinguish between Circles and SupportCircles in my searches, I do separate calls for each with Circle.findtaggedwith(tag) and SupportCircle.findtaggedwith(tag) respectively, and from the look of that query, I'll only get Circles from the first and SupportCircles from the second, right? (yes, I think... just checking 'cause of the unexpected behaviors I'm seeing)


    Sorry for the length of this and all the questions, but as I said above, perhaps some of you will know specifics of actsastaggable and others may now the general Rails answers and that will help me figure out how to make what I want to do work.

    Thanks in advance.

  • Avatar
    AlanSmith
    16 April 2008

    I am having this crazy problem where it ONLY shows up in testing.

    This is my test code
    <code>
    def test_should_destroy
    task1 = Task.new(:description => "tmp",
    :done => false,
    :user => User.find_by_login('admin'))
    assert task1.save
    assert task1.destroy
    end
    </code>

    This is my task model
    <code>
    class Task < ActiveRecord::Base
    acts_as_taggable
    acts_as_nested_set

    belongs_to :user
    validates_presence_of :user
    end
    </code>

    The result of running the test:
    1) Error:
    test_should_destroy(TaskTest):
    SystemStackError: stack level too deep
    /Users/alan/Projects/superb/vendor/plugins/acts_as_taggable_on_steroids/lib/acts_as_taggable.rb:220:in
    `reload_without_tag_list'
    /Users/alan/Projects/superb/vendor/plugins/acts_as_taggable_on_steroids/lib/acts_as_taggable.rb:220:in
    `reload'
    /Users/alan/Projects/superb/vendor/plugins/betternestedset/lib/better_nested_set.rb:161:in
    `before_destroy'
    /Library/Ruby/Gems/1.8/gems/activerecord-2.0.2/lib/active_record/callbacks.rb:322:in
    `send'
    /Library/Ruby/Gems/1.8/gems/activerecord-2.0.2/lib/active_record/callbacks.rb:322:in
    `callback'
    /Library/Ruby/Gems/1.8/gems/activerecord-2.0.2/lib/active_record/callbacks.rb:294:in
    `destroy_without_transactions'
    /Library/Ruby/Gems/1.8/gems/activerecord-2.0.2/lib/active_record/transactions.rb:104:in
    `destroy'
    /Library/Ruby/Gems/1.8/gems/activerecord-2.0.2/lib/active_record/connection_adapters/abstract/database_statements.rb:66:in
    `transaction'
    /Library/Ruby/Gems/1.8/gems/activerecord-2.0.2/lib/active_record/transactions.rb:80:in
    `transaction'
    /Library/Ruby/Gems/1.8/gems/activerecord-2.0.2/lib/active_record/transactions.rb:100:in
    `transaction'
    /Library/Ruby/Gems/1.8/gems/activerecord-2.0.2/lib/active_record/transactions.rb:104:in
    `destroy'
    ./test/unit/task_test.rb:37:in `test_should_destroy'
    /Library/Ruby/Gems/1.8/gems/activesupport-2.0.2/lib/active_support/testing/default.rb:7:in
    `run'

    If I comment out either "acts_as_taggable" OR "acts_as_nested_set", then the test runs fine.

    What is really driving me crazy is that in normal execution, the
    destroy works just fine.

    ANY help or IDEAS would be GREATLY GREATLY GREATLY appreciated.

  • Jeff Sharpe
    9 May 2008

    There is an optimization issue with tag_cloud. You are doing an Inner Join on Posts, which will probably do a full table scan, which is not needed and a problem when that table is rather large.

    Here is what you are generating for sql:

    SELECT tags.id, tags.name, COUNT() AS count FROM tags INNER JOIN taggings ON tags.id = taggings.tag_id INNER JOIN posts ON posts.id = taggings.taggable_id WHERE (taggings.taggable_type = 'Post') GROUP BY tags.id, tags.name HAVING COUNT() > 0 ORDER BY tags.name

    Should be:

    SELECT tags.id, tags.name, COUNT() AS count FROM tags INNER JOIN taggings ON tags.id = taggings.tag_id WHERE (taggings.taggable_type = 'Post') GROUP BY tags.id, tags.name HAVING COUNT() > 0 order by tags.name

  • Avatar
    12 May 2008

    For the life of me, I cant get this plugin to behave. It will save to my model's cachedtaglist field 100% of the time, but will not also save the tag association via the tags and taggings tables. The only thing that I can tell is special about my usage is that I am using Single Table Inheritance. Anyone else had this same issue? I'm desperate to know more ... of all the tagging plugins this is the only one supporting STI that I know of.

  • Avatar
    Peter Leonhardt
    12 May 2008

    Noticed a small bug in acts_as_taggable.rb in which, if the primary key for your model is not id, the findtaggedwith(string, :match_all => true) will fail out. Quick and easy fix is to change

    {tablename}.id to #{tablename}.#{primary_key}

    Cheers

  • Avatar
    13 May 2008

    @Sebjørn you might get that Uninitialized Constant error if you're using rails2: application config (like TagList.delimiter = ...) needs to go in a file in a config/initializers

    NB: would be helpful to update the howto above with this info.

  • Avatar
    majovrabel
    7 June 2008

    This is great. original actsastaggable did not work for me, but your pluggin does, thank a lot.

  • Avatar
    24 June 2008

    When I edit an entry, perhaps deleting a tag (sorry I forget the conditions), I sometimes get this. The taggings table has no 'id' column.


    ActiveRecord::StatementInvalid (Mysql::Error: #42S22Unknown column 'taggings.id' in 'field list': SELECT taggings.id AS t0r0, taggings.tag_id AS t0r1, taggings.taggable_id AS t0r2, taggings.taggable_type AS t0r3, tags.id AS t1r0, tags.name AS t1r1, tags.description AS t1r2, tags.created_at AS t1r3, tags.modified_at AS t1r4 FROM taggings LEFT OUTER JOIN tags ON tags.id = taggings.tagid WHERE (taggings.taggableid = 93 AND taggings.taggabletype = 'Encounter' AND (tag_id IN (34))) ): /usr/lib64/ruby/gems/1.8/gems/activerecord-2.0.2/lib/activerecord/connectionadapters/abstract_adapter.rb:150:in log&#x27; /usr/lib64/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/connection_adapters/mysql_adapter.rb:281:inexecute' /usr/lib64/ruby/gems/1.8/gems/activerecord-2.0.2/lib/activerecord/connectionadapters/mysql_adapter.rb:481:in select&#x27; /usr/lib64/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/connection_adapters/abstract/database_statements.rb:7:inselectallwithoutquerycache' /usr/lib64/ruby/gems/1.8/gems/activerecord-2.0.2/lib/activerecord/connectionadapters/abstract/query_cache.rb:53:in select_all&#x27; /usr/lib64/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/connection_adapters/abstract/query_cache.rb:74:incache_sql' /usr/lib64/ruby/gems/1.8/gems/activerecord-2.0.2/lib/activerecord/connectionadapters/abstract/query_cache.rb:53:in select_all&#x27; /usr/lib64/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/associations.rb:1242:inselectallrows' /usr/lib64/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/associations.rb:1124:in find_with_associations&#x27; /usr/lib64/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/associations.rb:1122:incatch' /usr/lib64/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/associations.rb:1122:in find_with_associations&#x27; /usr/lib64/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/base.rb:1232:infind_every' /usr/lib64/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/base.rb:503:in find&#x27; /usr/lib64/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/associations/has_many_association.rb:66:infind' /vendor/plugins/actsastaggableonsteroids/lib/actsastaggable.rb:177:in save_tags&#x27; /usr/lib64/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/connection_adapters/abstract/database_statements.rb:66:intransaction' /usr/lib64/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/transactions.rb:80:in transaction&#x27; /vendor/plugins/acts_as_taggable_on_steroids/lib/acts_as_taggable.rb:175:insave_tags'

  • Avatar
    Wylie
    14 July 2008

    I think the migrate file was just missing an id column for the tags table. I just added an id column as the primary key and auto incremented it. seems to work so far.

  • Avatar
    24 July 2008

    Has anyone had success with ActiveScaffold and filtering the output by giving a certain tag as input?

    I tried using something like #{Todo.findtaggedwith(params[:id]).first.taglist} in def conditionsfor_collection but can't seem to get over the limitation that there is no Foreign Key Field in the Todo Model and ActiveScaffold only looks within that model..

  • Avatar
    24 July 2008

    Has anyone had success with ActiveScaffold and filtering the output by giving a certain tag as input?

    I tried using something like #{Todo.findtaggedwith(params[:id]).first.taglist} in def conditionsfor_collection but can't seem to get over the limitation that there is no Foreign Key Field in the Todo Model and ActiveScaffold only looks within that model..

  • Avatar
    4 August 2008

    I seem to be getting a conflict between this and will_paginate for some reason, since going to Rails 2.1.

    Whenever i want to save an item which acts as taggable, it goes 'stack level too deep' and throws up the following ...

    vendor/plugins/will_paginate/lib/will_paginate/finder.rb:139:in `method_missing_without_paginate'
    vendor/plugins/will_paginate/lib/will_paginate/finder.rb:139:in `method_missing'
    vendor/plugins/acts_as_taggable_on_steroids/lib/acts_as_taggable.rb:172:in `save_tags'

    Anyone else having this problem?

  • Avatar
    YenTheFirst
    7 August 2008

    Running rails 2.1.0, I had a problem where , when removing tags from an object (and thus destroying taggings), sometimes I would get an error indicating that Tag::Class did not have a 'destroy_unused' method.

    After more testing, it appeared as though tag.rb wasn't being included, ever. I added a require for 'lib/tag' to the init.rb, and it works.

    Has anyone else had the same problem? Is that the correct solution?

  • Paul
    11 September 2008

    Great plugin, having fun so far. I'm using it more as a keyword search across a whole site, rather than just tagging on model. Is there a way to find all the objects with that tag across all the models that have been tagged, not just a model based lookup?

    I poured through the source code and couldn't find the answer easily...

  • Avatar
    Bob Dunne
    22 October 2008

    I'm getting an error when trying to save an object with new tags...

    I have seen other references to the issue but no solution.

    Any idea why I am getting this error?

    NoMethodError: undefined method `find_or_create_with_like_by_name' for Tag(id: integer, name: string):Class

    from c:/ruby/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:1672:in `method_missing'

    from C:/dev/apps/story/vendor/plugins/acts_as_taggable_on_steroids/lib/acts_as_taggable.rb:182:in `save_tags'

  • Mads
    17 November 2008

    TagList.delimiter should go into a file in 'config/initializers' to follow rails 2 conventions

  • Avatar
    24 November 2008

    I had the problem where tagcloud was an unknown method. I determined that my problem was that I had created a controller named "tags" that created a "tagshelper.rb" in app/helpers and was apparently shadowing the one provide my this plugin. After removing app/helpers/tagshelper.rb the tagcloud method was available.

  • Avatar
    9 December 2008

    Love this plugin, simple to use and really fast

  • Avatar
    Nick
    7 January 2009

    Great plugin! Much better than actsastaggable because it just works with no pain =)

  • Fifi
    15 February 2009

    Plugin not found: ["http://svn.viney.net.nz/things/rails/plugins/actsastaggabl eonsteroids"]

  • alphaRails
    15 February 2009

    Great plugin. I've used it in the past, but it seems that the link to the repo is not working.

  • MP
    1 May 2009

    I am pleased this works so well with Thinking Sphinx

  • Avatar
    11 May 2009

    I have found that this plugin does not work well with will_paginate in the latest version of Rails. The results count from the taggable call interfers with the pagination plugin's functioning.

    As a solution, I wrote a small library named paginationwithtags.rb.

    This library can be found here:

    http://my-svn.assembla.com/svn/paginationwithtags/

    Once again, this library provides a solution to the incompatibility problem between the latest versions of actsastaggableonsteroids and Mislav’s will_paginate.

  • Avatar
    Jonathan Viney
    6 June 2009

    Plugin has moved to github

    http://github.com/jviney/actsastaggableonsteroids

  • Avatar
    Rafael Magana
    14 June 2009

    http://github.com/jviney/actsastaggableonsteroids doesn't exists

  • Avatar
    Rafael Magana
    14 June 2009

    this is the correct URL => http://github.com/jviney/actsastaggableonsteroids

Add a comment