Plugins - Acts As Taggable On Steroids

StarAdd to favorites

acts_as_taggable_on_steroids

If you find this plugin useful, please consider a donation to show your support!

  http://www.paypal.com/cgi-bin/webscr?cmd=_send-money

  Email address: jonathan.viney@gmail.com

Instructions

This plugin is based on acts_as_taggable by DHH but includes extras such as tests, smarter tag assignment, and tag cloud calculations.

Installation

  ruby script/plugin install http://svn.viney.net.nz/things/rails/plugins/acts_as_taggable_on_steroids

Usage

Prepare database

Generate and apply the migration:

  ruby script/generate acts_as_taggable_migration
  rake db:migrate

Basic tagging

Let’s suppose users have many posts and we want those posts to have tags. The first step is to add acts_as_taggable to the Post class:

  class Post < ActiveRecord::Base
    acts_as_taggable

    belongs_to :user
  end

We can now use the tagging methods provided by acts_as_taggable, #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

Jonathan Viney

http://svn.viney.net.nz/things/rails/plugins/acts_as_taggable_on_steroids/

Rails' (MIT)

  • Currently 4.0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Model

Tags

Comments

Add a comment
Adam Jack 24 Jun 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' /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' /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' /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' /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' /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' /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' /usr/lib64/ruby/gems/1.8/gems/activerecord-2.0.2/lib/active_record/associations/has_many_association.rb:66:infind' /vendor/plugins/actsas_taggableonsteroids/lib/actsas_taggable.rb:177:in save_tags' /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' /vendor/plugins/acts_as_taggable_on_steroids/lib/acts_as_taggable.rb:175:insave_tags'

majovrabel 7 Jun 2008

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

Tim Diggins 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.

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

Russ Jones 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.

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

AlanSmith 16 Apr 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.
lunaclaire 11 Apr 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 actsas_taggableon_steroids 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 acts_as_taggable works...

Here's my problem -

1) Models -

class Group < ActiveRecord::Base

class Circle < Group

class SupportCircle < Circle

2) I have Circle declared as acts_as_taggable

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) actsas_taggable.rb's 'findtagged_with' 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 acts_as_ 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 acts_as_taggable 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.

rupert 1 Apr 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.

Jantzen 28 Mar 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

Dan Webb 27 Mar 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

Sebjørn 27 Mar 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 ;)

Chris 23 Mar 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.

Henry 9 Mar 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?

Maciek 5 Mar 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.

Maciek 5 Mar 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

jc 29 Feb 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.

jc 28 Feb 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?

Patrick 27 Feb 2008

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

Jeremy 21 Feb 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...

Jeremy 21 Feb 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.

Juan Matías 18 Feb 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?

Patrick 18 Feb 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

Gerlando 16 Feb 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?

Adam Wilson 2 Feb 2008

Migration not working!

I installed acts_as_taggable 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

Jonathan Viney 30 Jan 2008

Fix Tag.destroy_unused for Rails 2.0

Nobrow 28 Jan 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.

kcruci 23 Jan 2008
undefined method `tag_list'
kyanh 21 Jan 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

Giulio 20 Jan 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)
Ranieri Teixeira 18 Jan 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 acts_as_taggable?

Franz Woyzeck 16 Jan 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.

Geek 26 Dec 2007
  1. it generates sql with syntax error (I fixed it myself)
  2. tag_cloud method doesn't work (I gave up)
nardgo 21 Dec 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>

aubrey 20 Dec 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>

bart 17 Dec 2007

working from example below, I added this to actsas_taggable to find related tags. Not fully tested so use with caution. I modeled it closely after tagcounts <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(' AND ')

      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(['COUNT(*) &gt;= ?', options.delete(:at_least)]) if options[:at_least]
                at_most   = sanitize_sql(['COUNT(*) &lt;= ?', options.delete(:at_most)]) if options[:at_most]
                having    = [at_least, at_most].compact.join(' AND ')
                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.

stoney 10 Dec 2007

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

Yuval 4 Dec 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.

gc 29 Nov 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 acts_as_taggable 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>

Jason Galvin 21 Nov 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.

Paul 4 Nov 2007

Jaime, something like this should get you somewhere near:

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

Jaime Iniesta 3 Nov 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

Mario 24 Oct 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.
Yuval 23 Oct 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!

Jonathan Viney 21 Oct 2007

[22 October 2007]

  • Fix findtaggedwith using :match_all and :include.
josh 19 Oct 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

Jonathan Viney 15 Oct 2007

[15 October 2007]

  • Make findtaggedwith correctly apply :conditions

  • Add Tag.destroy_unused option.

Jonathan Viney 15 Oct 2007

Thanks Michal, I've applied a fix.

Michal Hantl 14 Oct 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!

Martin Gamsjaeger 14 Oct 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 'findor_createwithlikebyname' @line 158 in actsastaggable.rb doesn't work anymore? (I'm getting undefined method error). I changed it to 'findorcreateby_name' and it works now (obviously without the 'like' sql stuff, if that's what it was meant for :)

Any ideas?

Jonathan Viney 7 Oct 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.

Christian 6 Oct 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???

Jonathan Viney 4 Oct 2007

Yuval,

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

Yuval 3 Oct 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.

Yuval 2 Oct 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.

Jaime Iniesta 2 Oct 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 Oct 2007

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

YUval 2 Oct 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.

Jonathan Viney 2 Oct 2007

Thanks beltrachi, I've corrected the readme.

Jonathan Viney 2 Oct 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.

Jonathan Viney 2 Oct 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.

Yuval 1 Oct 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.

beltrachi 30 Sep 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!

Jonathan Viney 28 Sep 2007

[29 September 2007]

  • Add TagsHelper to assist with generating tag clouds and provide a simple example.
Jonathan Viney 27 Sep 2007

[27 September 2007]

  • Add #tag_counts method to get tag counts for a specific object's tags.
Organicveggie 26 Sep 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 acts_as_taggable.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/actsas_taggableonsteroids-matchall-and-postgres

Organicveggie 26 Sep 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?

Guillaume Dufloux 26 Sep 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 ;)

Guillaume Dufloux 26 Sep 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,

Jonathan Viney 16 Sep 2007

[17 September 2007]

  • Fix clearing of cached tag list when all tags removed.
Jonathan Viney 12 Sep 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.

ocher 11 Sep 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.

pixtur 5 Sep 2007

Please adjust you documentation. It should be

TagList.delimiter = " "

instead of

Tag.delimiter = " "

Yuval 3 Sep 2007

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

Jonathan Viney 1 Sep 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.

Jonathan Viney 1 Sep 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.

John N. 31 Aug 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.

Yuval 30 Aug 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.

Yuval 30 Aug 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.

Jonathan Viney 29 Aug 2007

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

Bryce Hammond 26 Aug 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 acts_as_taggable.rb.

Jonathan Viney 26 Aug 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]

Doug McBride 22 Aug 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.

Ray Daly 22 Aug 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

senthil 16 Aug 2007

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

Michael 15 Aug 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(/\,/, ' '))

Marco 7 Aug 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

Randy 6 Aug 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.

Dianna 1 Aug 2007

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

Jim Morris 30 Jul 2007

I have blogged about the method I use to paginate actsas_taggable with willpaginate.

http://blog.wolfman.com/articles/2007/07/30/paginating-actsas_taggable-with-willpaginate

Joe 26 Jul 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(' AND ')

      Tag.find(:all,
        :select     =&gt; 'tags.id, tags.name, COUNT(*) as count',
        :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; 'tags.id, tags.name HAVING COUNT(*) &gt; 0',
        :order      =&gt; 'COUNT(*) DESC'
      )
    end
Joe 25 Jul 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

Jonathan Viney 25 Jul 2007

Plugin changes:

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

  • Fix the :exclude option for findtaggedwith

dirx 24 Jul 2007

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

Chris Cameron 23 Jul 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!

Rainchen 20 Jul 2007

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

Yaron 19 Jul 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.

RainChen 19 Jul 2007

I hack the file lib/acts_as_taggable.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 = '#{name}' &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.

RainChen 19 Jul 2007

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

Chris 19 Jul 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?

Jonathan Viney 17 Jul 2007

Plugin changes:

  • Fix the migration on edge rails
Kip 15 Jul 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

Dimitry 15 Jul 2007

Is there any way to get count information for a Tag? I do tag = Tag.find_by_name("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!

riff42 11 Jul 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
J.F.Sebastian 10 Jul 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!

Mark 6 Jul 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.

Mark 6 Jul 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!

aurels 5 Jul 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!

Jonathan Viney 3 Jul 2007

Plugin changes:

  • Fix incorrect tagging when the case of the tag list is changed
  • Fix deprecated Tag.delimiter accessor
Jonathan Viney 30 Jun 2007

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

Joe 29 Jun 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 findor_createby_name 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

david 28 Jun 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.

Jonathan Viney 23 Jun 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.

Oshoma Momoh 22 Jun 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 actsas_taggable.rb, replace "count" with "count(*)" in the two lines containing the :atleast and :at_most 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.

Jonahan Viney 21 Jun 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.

Todd Lee 20 Jun 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 acts_as_taggable plugin)

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

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

I'm using windows xp/rails 1.2.3.

Jonathan Viney 15 Jun 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.

Scott Thorpe 14 Jun 2007

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

Anyone else having these problems?

Jonathan Viney 13 Jun 2007

Recent changes:

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

Enjoy! -Jonathan.

Peer Allan 11 Jun 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.

ruby ua 6 Jun 2007

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

Pierre Rigal 4 Jun 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-acts_as_taggable/"> Nuage de tag avec Ruby On Rails</a>

Madhan 2 Jun 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 acts_as_taggable.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.

Dominiek 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.

herval 26 May 2007

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

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

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
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
Vasil 30 Apr 2007

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

acts_as_taggable

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?

Eleo 26 Apr 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.

Jonathan Viney 23 Apr 2007

Plugin changes:

  • Fix tag_list to respect specific Tag.delimiter
mcarr 19 Apr 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/

mcarr 16 Apr 2007

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

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

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

mcarr 16 Apr 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>
mcarr 16 Apr 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"
dor kalev 3 Apr 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.

Shaun Doyle 3 Apr 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

Jonathan Viney 30 Mar 2007

Plugin changes:

  • Tag.delimiter to set the delimiter
  • findtaggedwith and :include => :tags has been fixed
Matthew Lang 28 Mar 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!

jvp 26 Mar 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!

Ramon 22 Mar 2007

For those looking for the schema to use to store the tags, you can use the schema defined in vendor/plugins/actsas_taggableon_steroids/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.

Matt Barnicle 16 Mar 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!

Fred 10 Mar 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

Sergei Barbarash 7 Mar 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 ...").

David Madden 3 Mar 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.

Aditya Raj 1 Mar 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..

Bryan 11 Feb 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.

bryan 11 Feb 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?

Jason 1 Feb 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.

Jason 29 Jan 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/actsas_taggableon_steroids-database-schema

Michael Sheakoski 26 Jan 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

Jamie van Dyke 23 Jan 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.

Thomas 17 Jan 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')

Andy 16 Jan 2007

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

Michael Sheakoski 3 Jan 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"

Abon 19 Dec 2006

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

THX

Search Plugins

Query syntax

Plugins by Category

Sponsors

Rails Kits: Get Code. Get Moving.
Recruiting software

Have a comment?