Delete duplicate records in different languages
This commit is contained in:
31
app/lib/poll_option_finder.rb
Normal file
31
app/lib/poll_option_finder.rb
Normal file
@@ -0,0 +1,31 @@
|
||||
class PollOptionFinder
|
||||
attr_reader :question
|
||||
|
||||
def initialize(question)
|
||||
@question = question
|
||||
end
|
||||
|
||||
def manageable_choices
|
||||
choices_map.select { |choice, ids| ids.count == 1 }
|
||||
end
|
||||
|
||||
def unmanageable_choices
|
||||
choices_map.reject { |choice, ids| ids.count == 1 }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def choices_map
|
||||
@choices_map ||= existing_choices.to_h do |choice|
|
||||
[choice, options.where("lower(title) = lower(?)", choice).distinct.ids]
|
||||
end
|
||||
end
|
||||
|
||||
def options
|
||||
question.question_options.joins(:translations).reorder(:id)
|
||||
end
|
||||
|
||||
def existing_choices
|
||||
question.answers.where(option_id: nil).distinct.pluck(:answer)
|
||||
end
|
||||
end
|
||||
@@ -37,26 +37,35 @@ namespace :polls do
|
||||
logger.info "Removing duplicate answers in polls"
|
||||
|
||||
Tenant.run_on_each do
|
||||
duplicate_ids = Poll::Answer.where(option_id: nil)
|
||||
.select(:question_id, :author_id, :answer)
|
||||
.group(:question_id, :author_id, :answer)
|
||||
.having("count(*) > 1")
|
||||
.pluck(:question_id, :author_id, :answer)
|
||||
Poll::Question.find_each do |question|
|
||||
manageable_titles = PollOptionFinder.new(question).manageable_choices.keys
|
||||
|
||||
duplicate_ids.each do |question_id, author_id, answer|
|
||||
poll_answers = Poll::Answer.where(question_id: question_id, author_id: author_id, answer: answer)
|
||||
question.question_options.each do |option|
|
||||
titles = option.translations.where(title: manageable_titles).select(:title).distinct
|
||||
|
||||
poll_answers.excluding(poll_answers.first).each do |poll_answer|
|
||||
poll_answer.delete
|
||||
author_ids = question.answers
|
||||
.where(answer: titles)
|
||||
.select(:author_id)
|
||||
.group(:author_id)
|
||||
.having("count(*) > 1")
|
||||
.pluck(:author_id)
|
||||
|
||||
tenant_info = " on tenant #{Tenant.current_schema}" unless Tenant.default?
|
||||
log_message = "Deleted duplicate record with ID #{poll_answer.id} " \
|
||||
"from the #{Poll::Answer.table_name} table " \
|
||||
"with question_id #{question_id}, " \
|
||||
"author_id #{author_id} " \
|
||||
"and answer #{answer}" + tenant_info.to_s
|
||||
logger.info(log_message)
|
||||
duplicate_records_logger.info(log_message)
|
||||
author_ids.each do |author_id|
|
||||
poll_answers = question.answers.where(option_id: nil, answer: titles, author_id: author_id)
|
||||
|
||||
poll_answers.excluding(poll_answers.first).each do |poll_answer|
|
||||
poll_answer.delete
|
||||
|
||||
tenant_info = " on tenant #{Tenant.current_schema}" unless Tenant.default?
|
||||
log_message = "Deleted duplicate record with ID #{poll_answer.id} " \
|
||||
"from the #{Poll::Answer.table_name} table " \
|
||||
"with question_id #{question.id}, " \
|
||||
"author_id #{author_id} " \
|
||||
"and answer #{poll_answer.answer}" + tenant_info.to_s
|
||||
logger.info(log_message)
|
||||
duplicate_records_logger.info(log_message)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -76,20 +85,13 @@ namespace :polls do
|
||||
end
|
||||
|
||||
questions.each do |question|
|
||||
options = question.question_options.joins(:translations).reorder(:id)
|
||||
existing_choices = question.answers.where(option_id: nil).distinct.pluck(:answer)
|
||||
option_finder = PollOptionFinder.new(question)
|
||||
|
||||
choices_map = existing_choices.to_h do |choice|
|
||||
[choice, options.where("lower(title) = lower(?)", choice).distinct.ids]
|
||||
end
|
||||
|
||||
manageable_choices, unmanageable_choices = choices_map.partition { |choice, ids| ids.count == 1 }
|
||||
|
||||
manageable_choices.each do |choice, ids|
|
||||
option_finder.manageable_choices.each do |choice, ids|
|
||||
question.answers.where(option_id: nil, answer: choice).update_all(option_id: ids.first)
|
||||
end
|
||||
|
||||
unmanageable_choices.each do |choice, ids|
|
||||
option_finder.unmanageable_choices.each do |choice, ids|
|
||||
tenant_info = " on tenant #{Tenant.current_schema}" unless Tenant.default?
|
||||
|
||||
if ids.count == 0
|
||||
|
||||
@@ -94,6 +94,40 @@ describe "polls tasks" do
|
||||
expect(Poll::Answer.count).to eq 2
|
||||
end
|
||||
|
||||
it "removes duplicate answers in different languages" do
|
||||
question = create(:poll_question_multiple, max_votes: 2)
|
||||
|
||||
create(:poll_question_option, question: question, title_en: "Yes", title_de: "Ja")
|
||||
create(:poll_question_option, question: question, title_en: "No", title_de: "Nein")
|
||||
create(:poll_question_option, question: question, title_en: "Maybe", title_de: "Vielleicht")
|
||||
|
||||
create(:poll_answer, author: user, question: question, answer: "Yes", option: nil)
|
||||
create(:poll_answer, author: user, question: question, answer: "Ja", option: nil)
|
||||
|
||||
expect(Poll::Answer.count).to eq 2
|
||||
|
||||
Rake.application.invoke_task("polls:remove_duplicate_answers")
|
||||
|
||||
expect(Poll::Answer.count).to eq 1
|
||||
end
|
||||
|
||||
it "does not remove duplicate answers when many options are possible" do
|
||||
question = create(:poll_question_multiple, title: "How do you pronounce it?", max_votes: 2)
|
||||
|
||||
create(:poll_question_option, question: question, title_en: "A", title_es: "EI")
|
||||
create(:poll_question_option, question: question, title_en: "E", title_es: "I")
|
||||
create(:poll_question_option, question: question, title_en: "I", title_es: "AI")
|
||||
|
||||
create(:poll_answer, question: question, author: user, answer: "I", option: nil)
|
||||
create(:poll_answer, question: question, author: user, answer: "AI", option: nil)
|
||||
|
||||
expect(Poll::Answer.count).to eq 2
|
||||
|
||||
Rake.application.invoke_task("polls:remove_duplicate_answers")
|
||||
|
||||
expect(Poll::Answer.count).to eq 2
|
||||
end
|
||||
|
||||
it "removes duplicate answers on tenants" do
|
||||
create(:tenant, schema: "answers")
|
||||
|
||||
@@ -176,6 +210,11 @@ describe "polls tasks" do
|
||||
user = create(:user, :level_two)
|
||||
question = create(:poll_question_multiple, :abc)
|
||||
|
||||
localized_question = create(:poll_question_multiple)
|
||||
create(:poll_question_option, question: localized_question, title_en: "Yes", title_de: "Ja")
|
||||
create(:poll_question_option, question: localized_question, title_en: "No", title_de: "Nein")
|
||||
create(:poll_question_option, question: localized_question, title_en: "Maybe", title_de: "Vielleicht")
|
||||
|
||||
answer_attributes = {
|
||||
question_id: question.id,
|
||||
author_id: user.id,
|
||||
@@ -185,14 +224,23 @@ describe "polls tasks" do
|
||||
answer = create(:poll_answer, answer_attributes)
|
||||
insert(:poll_answer, answer_attributes)
|
||||
|
||||
localized_answer_attributes = { author: user, question: localized_question, option: nil }
|
||||
localized_answer = create(:poll_answer, localized_answer_attributes.merge(answer: "Yes"))
|
||||
create(:poll_answer, localized_answer_attributes.merge(answer: "Ja"))
|
||||
|
||||
answer.reload
|
||||
localized_answer.reload
|
||||
|
||||
expect(answer.option_id).to be nil
|
||||
expect(localized_answer.option_id).to be nil
|
||||
|
||||
Rake.application.invoke_task("polls:populate_option_id")
|
||||
answer.reload
|
||||
localized_answer.reload
|
||||
|
||||
expect(Poll::Answer.count).to eq 1
|
||||
expect(Poll::Answer.count).to eq 2
|
||||
expect(answer.option_id).to eq question.question_options.find_by(title: "Answer A").id
|
||||
expect(localized_answer.option_id).to eq localized_question.question_options.find_by(title: "Yes").id
|
||||
end
|
||||
|
||||
it "populates the option_id column on tenants" do
|
||||
|
||||
Reference in New Issue
Block a user