Friday, December 14, 2007

Acts as Taggable on Steroids - the missing muscle

Recently i decided to use Acts as Taggable on Steriods rather than my old favorite, It’s non ‘roided cousin. AATOS is a nice alternative in my opinion because of it’s polymorphic STI taggings. It makes my database a little DRY-er and DRY is always good. Well, in terms of code, anyway.

But nothing worthwhile is without a little struggle and quickly the undeveloped muscle of AATOS was blindingly apparent.

My flash tag cloud browser, relies heavily on the ability to query for related tags. A method that the sterioded version of taggable was missing.

Undaunted, i sent Mr Steriod to the gym for a little training, and now his undeveloped muscle is bulging.


Add the little patch below and Mr Steriod will be squat-thrusting related tags in a jiffy.





module ActiveRecord
module Acts
module Taggable
module SingletonMethods

def find_related_tags(list, options={})
tags = escape_tags(list).join(',')
return [] if tags.blank?
related = find_tagged_with(list)
return [] if related.blank?
related_ids = related.map(& :id).map(& :to_s).join(', ')
Tag.find :all, options.merge({
:select => 'tags.*, COUNT(tags.id) AS count',
:from => 'tags',
:joins => "JOIN taggings ON taggings.taggable_type = '#{base_class.name}'
AND taggings.taggable_id IN (#{related_ids})
AND taggings.tag_id = tags.id",
:order => options[:order] || 'count DESC, tags.name',
:group => "tags.id, tags.name HAVING count > 0 AND tags.name NOT IN (#{tags})"
})
end

protected

def escape_tags(list)
list.map { |t| t.to_s.strip.downcase }.
reject { |t| t.blank? }.
uniq.
map { |t| "'#{connection.quote_string(t)}'" }
end

end
end
end
end