module Calagator module DuplicateChecking class DuplicateSquasher < Struct.new(:master, :duplicates, :model_name, :failure, :success) def duplicates Array(super) end def valid? name = model_name.split('::').last self.failure = "A master #{name} must be selected." if master.blank? self.failure = "At least one duplicate #{name} must be selected." if duplicates.empty? self.failure = "The master #{name} could not be squashed into itself." if duplicates.include?(master) failure.blank? end def squash if valid? duplicates.each do |duplicate| SingleSquasher.new(master, duplicate, model_name).squash end name = model_name.split('::').last self.success = "Squashed duplicate #{name.pluralize} #{duplicates.map(&:title).sort} into master #{master.id}." end self end class SingleSquasher < Struct.new(:master, :duplicate, :model_name) def squash # Transfer any venues that use this now duplicate venue as a master if duplicate.duplicates.any? DuplicateSquasher.new(master, duplicate.duplicates, model_name).squash end squash_associations duplicate.update_attribute(:duplicate_of, master) duplicate end private def squash_associations # Transfer any has_many associations of this model to the master master.class.reflect_on_all_associations(:has_many).each do |association| next if association.name == :duplicates next if master.class.duplicate_squashing_ignores_associations.include?(association.name) # Handle tags - can't simply reassign, need to be unique, and they may have some of the same tags if association.name == :tag_taggings squash_tags else squash_association association end end end # custom behavior for tags, concatentate the two objects tag strings together def squash_tags master.tag_list = master.tag_list + duplicate.tag_list master.save_tags end def squash_association(association) foreign_objects = duplicate.send(association.name) foreign_objects.each do |object| object.update_attribute(association.foreign_key, master.id) end end end end end end