From d5716c42607a8f43055dd3e2a34c86aa0b4078fa Mon Sep 17 00:00:00 2001 From: Urban Rotnik Date: Thu, 26 Sep 2019 08:47:43 +0200 Subject: [PATCH] Add rake task for fixing invalid canvas positions --- lib/tasks/my_modules.rake | 40 +++++++++++++++++++++++++++++++ spec/lib/tasks/my_modules_spec.rb | 40 +++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 lib/tasks/my_modules.rake create mode 100644 spec/lib/tasks/my_modules_spec.rb diff --git a/lib/tasks/my_modules.rake b/lib/tasks/my_modules.rake new file mode 100644 index 000000000..615f6cf23 --- /dev/null +++ b/lib/tasks/my_modules.rake @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +# On production around 2k records for repair, for production DB it tooked cca 1 min + +# rubocop:disable Metrics/BlockLength +namespace :my_modules do + desc 'Find new positions on canvas for already taken coordiantes' + task fix_positions: :environment do + query = MyModule.select('COUNT(*) as duplicates', :x, :y, :experiment_id) + .where(archived: false) + .group(:x, :y, :experiment_id) + .having('COUNT(*)>1') + + Rails.logger.info '*********************************************************************************' + Rails.logger.info "You have to relocate #{query.sum { |a| a.duplicates - 1 }} tasks" + Rails.logger.info '*********************************************************************************' + + query.each do |row| + tasks_to_update = MyModule.where(experiment_id: row.experiment, x: row.x, y: row.y, archived: false) + .order(created_at: :asc) + .offset(1) + + tasks_to_update.find_each do |task| + coordinates = task.get_new_position + task.attributes = coordinates + begin + task.save! + Rails.logger.info "Relocated task with ID #{task.id}" + rescue ActiveRecord::RecordInvalid => e + Rails.logger.error "Unable to save task with ID #{task.id}: #{e.message}" + end + end + end + + Rails.logger.info '*********************************************************************************' + Rails.logger.info "You have #{query.reload.sum { |a| a.duplicates - 1 }} tasks on invalid positions" + Rails.logger.info '*********************************************************************************' + end +end +# rubocop:enable Metrics/BlockLength diff --git a/spec/lib/tasks/my_modules_spec.rb b/spec/lib/tasks/my_modules_spec.rb new file mode 100644 index 000000000..afb84ad6b --- /dev/null +++ b/spec/lib/tasks/my_modules_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'my_modules:fix_positions' do + include_context 'rake' + + before(:all) do + experiment = create :experiment + + 100.times do + create :my_module, experiment: experiment + end + + # set 30 tasks same position + my_modules_with_same_position = MyModule.limit(10) + my_modules_with_same_position.update_all(x: 0, y: 0) + + # 1 module should be invalid + my_modules_with_same_position.second.update_column(:name, 'a') + + my_modules_with_same_position.third.update_column(:archived, true) + end + context 'when record is valid except position' do + it 'changes position for my_module' do + expect { subject.invoke }.to(change { MyModule.find(5).y }) + end + end + + context 'when record is invalid' do + it 'remains error on position' do + subject.invoke + my_module = MyModule.find_by(name: 'a') + my_module.valid? + + expect(my_module.errors.messages[:position]) + .to(eq ['and Y position has already been taken by another task in the experiment.']) + end + end +end