https://github.com/bradphelan/rocket_tag
is the new library I just created yesterday. It is implemented using the Ernie Miller gemstone where possible, so all the scary SQL needed to properly implement the tag library is pretty clean.
compare act_as_taggable_ons
def tagged_with(tags, options = {}) tag_list = ActsAsTaggableOn::TagList.from(tags) empty_result = scoped(:conditions => "1 = 0") return empty_result if tag_list.empty? joins = [] conditions = [] context = options.delete(:on) alias_base_name = undecorated_table_name.gsub('.','_') if options.delete(:exclude) tags_conditions = tag_list.map { |t| sanitize_sql(["#{ActsAsTaggableOn::Tag.table_name}.name #{like_operator} ?", t]) }.join(" OR ") conditions << "#{table_name}.#{primary_key} NOT IN (SELECT #{ActsAsTaggableOn::Tagging.table_name}.taggable_id FROM #{ActsAsTaggableOn::Tagging.table_name} JOIN #{ActsAsTaggableOn::Tag.table_name} ON #{ActsAsTaggableOn::Tagging.table_name}.tag_id = #{ActsAsTaggableOn::Tag.table_name}.#{ActsAsTaggableOn::Tag.primary_key} AND (#{tags_conditions}) WHERE #{ActsAsTaggableOn::Tagging.table_name}.taggable_type = #{quote_value(base_class.name)})" elsif options.delete(:any)
in rocket_tags
def with_tag_context context if context where{taggings.context == my{context} } else where{} end end def tagged_with tags_list, options = {} on = options.delete :on all = options.delete :all q = if all joins{tags}.where{ id.in( my{self}. select{id}. joins{tags}. where{tags.name.in(my{tags_list})}. group{~id}. having{count(~id)==my{tags_list.length}}. with_tag_context(my{on}) ) } else joins{tags}.where{tags.name.in(my{tags_list})}.with_tag_context(on) end q.select{"distinct #{my{table_name}}.*"} end
which is much cleaner, although I do not claim to have processed every function that act_as_taggable_on performed. There is always tomorrow :)
So, if you want the tag library you can dive in and add features to rocket_tag, perhaps this is what you want.
It also takes care of performance and avoids the N + 1 issue when loading related tags. It is worth a look, but at the moment it is very alpha, and I will add features as required by my project.
BTW. Thanks to action-like-taggable-on. I do not cry in the library. I borrowed the schema and ideas from it, but when I wanted to fix my own functions, I felt that the SQL style in the code is pretty hard to understand and after using https://github.com/ernie/squeel for my AR queries, I felt it was better to work with a clean list.
RocketTag also has a comprehensive rspec test suite https://github.com/bradphelan/rocket_tag/blob/master/spec/rocket_tag/taggable_spec.rb