Add task to delete duplicate poll partial results
Adds rake task "polls:remove_duplicate_partial_results" to delete duplicated rows in "poll_partial_results" made before the DB was strict about duplicates. Duplicates are considered only for records without "option_id", grouping by: (question_id, booth_assignment_id, date, answer). We keep the first one and delete the rest, per tenant. The controller use: Poll::PartialResult.find_or_initialize_by(booth_assignment_id, date, question_id, answer) which is not a strong protection against race conditions. Without a unique index at the DB level, duplicates could be created. This task cleans up any existing duplicates.
This commit is contained in:
@@ -3,8 +3,10 @@ namespace :consul do
|
||||
task execute_release_tasks: ["settings:rename_setting_keys",
|
||||
"settings:add_new_settings",
|
||||
"cache:clear",
|
||||
"execute_release_2.3.0_tasks"]
|
||||
"execute_release_2.4.0_tasks"]
|
||||
|
||||
desc "Runs tasks needed to upgrade from 2.2.2 to 2.3.0"
|
||||
task "execute_release_2.3.0_tasks": []
|
||||
desc "Runs tasks needed to upgrade from 2.3.1 to 2.4.0"
|
||||
task "execute_release_2.4.0_tasks": [
|
||||
"polls:remove_duplicate_partial_results"
|
||||
]
|
||||
end
|
||||
|
||||
@@ -107,4 +107,44 @@ namespace :polls do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
desc "Removes duplicate poll partial results"
|
||||
task remove_duplicate_partial_results: :environment do
|
||||
logger = ApplicationLogger.new
|
||||
duplicate_records_logger = DuplicateRecordsLogger.new
|
||||
|
||||
logger.info "Removing duplicate partial results in polls"
|
||||
|
||||
Tenant.run_on_each do
|
||||
duplicate_ids = Poll::PartialResult.where(option_id: nil)
|
||||
.select(:question_id, :booth_assignment_id, :date, :answer)
|
||||
.group(:question_id, :booth_assignment_id, :date, :answer)
|
||||
.having("count(*) > 1")
|
||||
.pluck(:question_id, :booth_assignment_id, :date, :answer)
|
||||
|
||||
duplicate_ids.each do |question_id, booth_assignment_id, date, answer|
|
||||
partial_results = Poll::PartialResult.where(
|
||||
question_id: question_id,
|
||||
booth_assignment_id: booth_assignment_id,
|
||||
date: date,
|
||||
answer: answer,
|
||||
option_id: nil
|
||||
)
|
||||
|
||||
partial_results.excluding(partial_results.first).each do |partial_result|
|
||||
partial_result.delete
|
||||
|
||||
tenant_info = " on tenant #{Tenant.current_schema}" unless Tenant.default?
|
||||
log_message = "Deleted duplicate record with ID #{partial_result.id} " \
|
||||
"from the #{Poll::PartialResult.table_name} table " \
|
||||
"with question_id #{question_id}, " \
|
||||
"booth_assignment_id #{booth_assignment_id}, " \
|
||||
"date #{date} " \
|
||||
"and answer #{answer}" + tenant_info.to_s
|
||||
logger.info(log_message)
|
||||
duplicate_records_logger.info(log_message)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -223,4 +223,88 @@ describe "polls tasks" do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "polls:remove_duplicate_partial_results" do
|
||||
before { Rake::Task["polls:remove_duplicate_partial_results"].reenable }
|
||||
|
||||
let(:booth_assignment) { create(:poll_booth_assignment) }
|
||||
let(:other_booth_assignment) { create(:poll_booth_assignment) }
|
||||
|
||||
it "removes duplicate partial results" do
|
||||
question = create(:poll_question_multiple, :abcde, poll: poll, max_votes: 4)
|
||||
|
||||
result_attributes = {
|
||||
question_id: question.id,
|
||||
booth_assignment_id: booth_assignment.id,
|
||||
date: Date.current,
|
||||
answer: "Answer A",
|
||||
option_id: nil
|
||||
}
|
||||
other_result_attributes = result_attributes.merge(answer: "Answer B")
|
||||
|
||||
result = create(:poll_partial_result, result_attributes)
|
||||
other_result = create(:poll_partial_result, other_result_attributes)
|
||||
other_booth_result = create(:poll_partial_result,
|
||||
result_attributes.merge(booth_assignment_id: other_booth_assignment.id))
|
||||
|
||||
2.times { insert(:poll_partial_result, result_attributes) }
|
||||
insert(:poll_partial_result, other_result_attributes)
|
||||
insert(:poll_partial_result, result_attributes.merge(booth_assignment_id: other_booth_assignment.id))
|
||||
|
||||
expect(Poll::PartialResult.count).to eq 7
|
||||
|
||||
Rake.application.invoke_task("polls:remove_duplicate_partial_results")
|
||||
|
||||
expect(Poll::PartialResult.count).to eq 3
|
||||
expect(Poll::PartialResult.all).to match_array [result, other_result, other_booth_result]
|
||||
end
|
||||
|
||||
it "does not remove partial results with the same text and different options" do
|
||||
question = create(:poll_question_multiple, :abcde, max_votes: 4)
|
||||
option_a = question.question_options.find_by(title: "Answer A")
|
||||
option_b = question.question_options.find_by(title: "Answer B")
|
||||
|
||||
result_attributes = {
|
||||
question: question,
|
||||
booth_assignment_id: booth_assignment.id,
|
||||
date: Date.current,
|
||||
answer: "Answer A"
|
||||
}
|
||||
create(:poll_partial_result, result_attributes.merge(option: option_a))
|
||||
insert(:poll_partial_result, result_attributes.merge(option_id: option_b.id))
|
||||
|
||||
expect(Poll::PartialResult.count).to eq 2
|
||||
|
||||
Rake.application.invoke_task("polls:remove_duplicate_partial_results")
|
||||
|
||||
expect(Poll::PartialResult.count).to eq 2
|
||||
end
|
||||
|
||||
it "removes duplicate partial results on tenants" do
|
||||
create(:tenant, schema: "partial_results")
|
||||
|
||||
Tenant.switch("partial_results") do
|
||||
question = create(:poll_question_multiple, :abc)
|
||||
booth_assignment = create(:poll_booth_assignment)
|
||||
|
||||
result_attributes = {
|
||||
question_id: question.id,
|
||||
booth_assignment_id: booth_assignment.id,
|
||||
date: Date.current,
|
||||
answer: "Answer A",
|
||||
option_id: nil
|
||||
}
|
||||
create(:poll_partial_result, result_attributes)
|
||||
insert(:poll_partial_result, result_attributes)
|
||||
|
||||
expect(Poll::PartialResult.count).to eq 2
|
||||
end
|
||||
|
||||
Rake.application.invoke_task("polls:remove_duplicate_partial_results")
|
||||
|
||||
Tenant.switch("partial_results") do
|
||||
expect(Poll::PartialResult.count).to eq 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user