// description of your code here
module ActiveRecord
module Acts
module Taggable
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def acts_as_taggable(options = {})
write_inheritable_attribute(:acts_as_taggable_options, {
:taggable_type => ActiveRecord::Base.send(:class_name_of_active_record_descendant, self).to_s,
:from => options[:from]
})
class_inheritable_reader :acts_as_taggable_options
has_many :taggings, :as => :taggable, :dependent => true
has_many :tags, :through => :taggings
include ActiveRecord::Acts::Taggable::InstanceMethods
extend ActiveRecord::Acts::Taggable::SingletonMethods
end
end
module SingletonMethods
def find_tagged_with(list, options = {})
local_options = { :limit => 1000, :offset => 0 }.merge(options)
find_by_sql([
"SELECT DISTINCT #{table_name}.* FROM #{table_name}, tags, taggings " +
"WHERE #{table_name}.#{primary_key} = taggings.taggable_id " +
"AND taggings.taggable_type = ? " +
"AND taggings.tag_id = tags.id AND tags.name IN (?) #{"AND (#{local_options[:conditions]})" if local_options[:conditions]} LIMIT ? OFFSET ?",
acts_as_taggable_options[:taggable_type], list, local_options[:limit], local_options[:offset]
])
end
def count_tagged_with(list, options = {})
local_options = {}.merge(options)
find_by_sql([
"SELECT COUNT(DISTINCT #{table_name}.#{primary_key}) AS cnt FROM #{table_name}, tags, taggings " +
"WHERE #{table_name}.#{primary_key} = taggings.taggable_id " +
"AND taggings.taggable_type = ? " +
"AND taggings.tag_id = tags.id AND tags.name IN (?) #{"AND (#{local_options[:conditions]}) " if local_options[:conditions]}",
acts_as_taggable_options[:taggable_type], list
]).first.cnt.to_i
end
def find_tagged_with_intersecting(list, options = {})
local_options = { :limit => 1000, :offset => 0 }.merge(options)
find_by_sql([
"SELECT DISTINCT #{table_name}.* FROM #{table_name}, tags, taggings " +
"WHERE #{table_name}.#{primary_key} = taggings.taggable_id " +
"AND taggings.taggable_type = ? " +
"AND taggings.tag_id = tags.id AND tags.name IN (?) #{"AND (#{local_options[:conditions]}) " if local_options[:conditions]} GROUP BY #{table_name}.id HAVING COUNT(#{table_name}.id) = #{list.size} LIMIT ? OFFSET ?",
acts_as_taggable_options[:taggable_type], list, local_options[:limit], local_options[:offset]
])
end
def count_tagged_with_intersecting(list, options = {})
local_options = {}.merge(options)
find_by_sql([
"SELECT COUNT(*) AS cnt FROM (SELECT #{table_name}.#{primary_key} AS cnt FROM #{table_name}, tags, taggings " +
"WHERE #{table_name}.#{primary_key} = taggings.taggable_id " +
"AND taggings.taggable_type = ? " +
"AND taggings.tag_id = tags.id AND tags.name IN (?) " +
"#{"AND (#{local_options[:conditions]})" if local_options[:conditions]} " +
"GROUP BY taggings.taggable_id HAVING COUNT(taggings.taggable_id) = #{list.size}) AS x",
acts_as_taggable_options[:taggable_type], list
]).first.cnt.to_i
end
end
module InstanceMethods
def tag_with(list)
Tag.transaction do
taggings.destroy_all
Tag.parse(list).each do |name|
if acts_as_taggable_options[:from]
send(acts_as_taggable_options[:from]).tags.find_or_create_by_name(name).on(self)
else
Tag.find_or_create_by_name(name).on(self)
end
end
end
end
def tag_list
tags.collect { |tag| tag.name.include?(" ") ? "'#{tag.name}'" : tag.name }.join(" ")
end
end
end
end
end