def acts_as_taggable(options = {})
options = { :collection => :tags, :tag_class_name => 'Tag' }.merge(options)
collection_name = options[:collection]
tag_model = options[:tag_class_name].constantize
default_join_table = "#{tag_model.table_name}_#{self.table_name}"
options[:join_table] ||= default_join_table
options[:foreign_key] ||= self.name.to_s.foreign_key
options[:association_foreign_key] ||= tag_model.to_s.foreign_key
if join_class_name = options[:join_class_name]
Object.class_eval "class #{join_class_name} < ActiveRecord::Base; set_table_name '#{options[:join_table]}' end" unless Object.const_defined?(join_class_name)
join_model = join_class_name.constantize
tagged = self
join_model.class_eval do
belongs_to :tag, :class_name => tag_model.to_s
belongs_to :tagged, :class_name => tagged.name.to_s
define_method(:name) { self['name'] ||= tag.name }
end
options[:class_name] ||= join_model.to_s
tag_pk, tag_fk = tag_model.primary_key, options[:association_foreign_key]
t, jt = tag_model.table_name, join_model.table_name
options[:finder_sql] ||= "SELECT #{jt}.*, #{t}.name AS name FROM #{jt}, #{t} WHERE #{jt}.#{tag_fk} = #{t}.#{tag_pk} AND #{jt}.#{options[:foreign_key]} = \#{quoted_id}"
else
join_model = nil
end
write_inheritable_attribute(:tag_foreign_key, options[:association_foreign_key])
write_inheritable_attribute(:taggable_foreign_key, options[:foreign_key])
write_inheritable_attribute(:tag_collection_name, collection_name)
write_inheritable_attribute(:tag_model, tag_model)
write_inheritable_attribute(:tags_join_model, join_model)
write_inheritable_attribute(:tags_join_table, options[:join_table])
write_inheritable_attribute(:tag_options, options)
[ :collection, :tag_class_name, :join_class_name ].each { |key| options.delete(key) }
[ :join_table, :association_foreign_key ].each { |key| options.delete(key) } if join_model
class_eval do
include ActiveRecord::Acts::Taggable::InstanceMethods
extend ActiveRecord::Acts::Taggable::SingletonMethods
class_inheritable_reader :tag_collection_name, :tag_model, :tags_join_model,
:tags_options, :tags_join_table,
:tag_foreign_key, :taggable_foreign_key
if join_model
has_many collection_name, options
else
has_and_belongs_to_many collection_name, options
end
end
end