From e92e9947b856b7d53d5302cf9cffe53f378e7c16 Mon Sep 17 00:00:00 2001 From: Matchu Date: Mon, 15 Nov 2010 21:15:33 -0500 Subject: [PATCH] rake task to, hopefully, repair duplicate pet state ids cleanly --- app/models/pet_state.rb | 52 ++++++++++++++++++++++++++++++-- lib/tasks/repair_pet_states.rake | 6 ++++ 2 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 lib/tasks/repair_pet_states.rake diff --git a/app/models/pet_state.rb b/app/models/pet_state.rb index 5e64b00d..d864d3be 100644 --- a/app/models/pet_state.rb +++ b/app/models/pet_state.rb @@ -1,7 +1,8 @@ class PetState < ActiveRecord::Base SwfAssetType = 'biology' - has_one :contribution, :as => :contributed + has_many :contributions, :as => :contributed # in case of duplicates being merged + has_many :outfits has_many :parent_swf_asset_relationships, :foreign_key => 'parent_id', :conditions => {:swf_asset_type => SwfAssetType} has_many :swf_assets, :through => :parent_swf_asset_relationships, :source => :biology_asset @@ -10,6 +11,34 @@ class PetState < ActiveRecord::Base alias_method :swf_asset_ids_from_association, :swf_asset_ids + def reassign_children_to!(main_pet_state) + self.contributions.each do |contribution| + contribution.contributed = main_pet_state + contribution.save + end + self.outfits.each do |outfit| + outfit.pet_state = main_pet_state + outfit.save + end + ParentSwfAssetRelationship.where(ParentSwfAssetRelationship.arel_table[:parent_id].eq(self.id)).delete_all + end + + def reassign_duplicates! + raise "This may only be applied to pet states that represent many duplicate entries" unless duplicate_ids + pet_states = duplicate_ids.split(',').map do |id| + PetState.find(id.to_i) + end + main_pet_state = pet_states.shift + pet_states.each do |pet_state| + pet_state.reassign_children_to!(main_pet_state) + pet_state.destroy + end + end + + def sort_swf_asset_ids! + self.swf_asset_ids = swf_asset_ids.split(',').map(&:to_i).sort.join(',') + end + def swf_asset_ids self['swf_asset_ids'] end @@ -25,7 +54,7 @@ class PetState < ActiveRecord::Base swf_asset_ids << asset_info[:part_id].to_i end end - swf_asset_ids_str = swf_asset_ids.join(',') + swf_asset_ids_str = swf_asset_ids.sort.join(',') if pet_type.new_record? pet_state = self.new :swf_asset_ids => swf_asset_ids_str else @@ -71,4 +100,23 @@ class PetState < ActiveRecord::Base pet_state.parent_swf_asset_relationships = relationships pet_state end + + def self.repair_all! + self.transaction do + self.all.each do |pet_state| + pet_state.sort_swf_asset_ids! + pet_state.save + end + + self. + select('pet_states.pet_type_id, pet_states.swf_asset_ids, GROUP_CONCAT(DISTINCT pet_states.id) AS duplicate_ids'). + joins('INNER JOIN pet_states ps2 ON pet_states.pet_type_id = ps2.pet_type_id AND pet_states.swf_asset_ids = ps2.swf_asset_ids'). + group('pet_states.pet_type_id, pet_states.swf_asset_ids'). + having('count(*) > 1'). + all. + each do |pet_state| + pet_state.reassign_duplicates! + end + end + end end diff --git a/lib/tasks/repair_pet_states.rake b/lib/tasks/repair_pet_states.rake new file mode 100644 index 00000000..f9d0d9bb --- /dev/null +++ b/lib/tasks/repair_pet_states.rake @@ -0,0 +1,6 @@ +namespace :pet_states do + desc "Sort pet state SWFs, then remove duplicates and reassign children" + task :repair => :environment do + PetState.repair_all! + end +end