orbit-basic/lib/orbit_tag/taggable.rb

82 lines
2.0 KiB
Ruby

module OrbitTag
module Taggable
def self.included(base)
base.extend ClassMethods
base.class_eval 'taggable'
end
module ClassMethods
def taggable
class_eval do
field :tags_to_destroy, type: Array, default: []
field :tagged_ids, type: Array, default: []
has_many :taggings, as: :taggable, autosave: true, dependent: :destroy
accepts_nested_attributes_for :taggings, allow_destroy: true
after_save :remove_taggings, unless: Proc.new{self.tags_to_destroy.blank?}
end
send :include, InstanceMethods
end
end
module InstanceMethods
def remove_id(id)
self.class.without_callback(:save, :after, :remove_taggings) do
self.update_attribute(:tagged_ids, self.tagged_ids - [id.to_s])
end
end
def sorted_tags
if tags.blank?
[]
else
tag_array = tags.inject([]){ |result, value|
result << [value.name, value]
}
tag_array.sort.map{|x| x[1] }
end
end
def tags
self.taggings.blank? ? [] : self.taggings.map{|t| t.tag}.compact
end
def tags=(tag_ids)
tag_ids = [tag_ids].flatten
tag_ids.delete_if{|e| e.match(/^[0-1]$|^$/)}
ids = self.taggings.blank? ? [] : self.taggings.map{|t| t.tag.id}
tag_ids.each do |tag_id|
unless ids.include? tag_id
self.taggings.build(tag_id: tag_id)
end
end
self.tags_to_destroy = self.taggings.where(:tag_id.in => (ids - tag_ids)).map{|t| t.id}
self.tagged_ids = tag_ids
end
def tag_ids
self.tags.map{|t| t.id}
end
def tag_ids=(ids)
self.tags = ids
end
private
def remove_taggings
self.taggings.where(:_id.in => self.tags_to_destroy).destroy
self.class.without_callback(:save, :after, :remove_taggings) do
self.update_attribute(:tags_to_destroy, [])
end
end
end
end
end