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,14 +37,21 @@ namespace :polls do
|
|||||||
logger.info "Removing duplicate answers in polls"
|
logger.info "Removing duplicate answers in polls"
|
||||||
|
|
||||||
Tenant.run_on_each do
|
Tenant.run_on_each do
|
||||||
duplicate_ids = Poll::Answer.where(option_id: nil)
|
Poll::Question.find_each do |question|
|
||||||
.select(:question_id, :author_id, :answer)
|
manageable_titles = PollOptionFinder.new(question).manageable_choices.keys
|
||||||
.group(:question_id, :author_id, :answer)
|
|
||||||
.having("count(*) > 1")
|
|
||||||
.pluck(:question_id, :author_id, :answer)
|
|
||||||
|
|
||||||
duplicate_ids.each do |question_id, author_id, answer|
|
question.question_options.each do |option|
|
||||||
poll_answers = Poll::Answer.where(question_id: question_id, author_id: author_id, answer: answer)
|
titles = option.translations.where(title: manageable_titles).select(:title).distinct
|
||||||
|
|
||||||
|
author_ids = question.answers
|
||||||
|
.where(answer: titles)
|
||||||
|
.select(:author_id)
|
||||||
|
.group(:author_id)
|
||||||
|
.having("count(*) > 1")
|
||||||
|
.pluck(:author_id)
|
||||||
|
|
||||||
|
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_answers.excluding(poll_answers.first).each do |poll_answer|
|
||||||
poll_answer.delete
|
poll_answer.delete
|
||||||
@@ -52,15 +59,17 @@ namespace :polls do
|
|||||||
tenant_info = " on tenant #{Tenant.current_schema}" unless Tenant.default?
|
tenant_info = " on tenant #{Tenant.current_schema}" unless Tenant.default?
|
||||||
log_message = "Deleted duplicate record with ID #{poll_answer.id} " \
|
log_message = "Deleted duplicate record with ID #{poll_answer.id} " \
|
||||||
"from the #{Poll::Answer.table_name} table " \
|
"from the #{Poll::Answer.table_name} table " \
|
||||||
"with question_id #{question_id}, " \
|
"with question_id #{question.id}, " \
|
||||||
"author_id #{author_id} " \
|
"author_id #{author_id} " \
|
||||||
"and answer #{answer}" + tenant_info.to_s
|
"and answer #{poll_answer.answer}" + tenant_info.to_s
|
||||||
logger.info(log_message)
|
logger.info(log_message)
|
||||||
duplicate_records_logger.info(log_message)
|
duplicate_records_logger.info(log_message)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
desc "populates the poll answers option_id column"
|
desc "populates the poll answers option_id column"
|
||||||
task populate_option_id: :remove_duplicate_answers do
|
task populate_option_id: :remove_duplicate_answers do
|
||||||
@@ -76,20 +85,13 @@ namespace :polls do
|
|||||||
end
|
end
|
||||||
|
|
||||||
questions.each do |question|
|
questions.each do |question|
|
||||||
options = question.question_options.joins(:translations).reorder(:id)
|
option_finder = PollOptionFinder.new(question)
|
||||||
existing_choices = question.answers.where(option_id: nil).distinct.pluck(:answer)
|
|
||||||
|
|
||||||
choices_map = existing_choices.to_h do |choice|
|
option_finder.manageable_choices.each do |choice, ids|
|
||||||
[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|
|
|
||||||
question.answers.where(option_id: nil, answer: choice).update_all(option_id: ids.first)
|
question.answers.where(option_id: nil, answer: choice).update_all(option_id: ids.first)
|
||||||
end
|
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?
|
tenant_info = " on tenant #{Tenant.current_schema}" unless Tenant.default?
|
||||||
|
|
||||||
if ids.count == 0
|
if ids.count == 0
|
||||||
|
|||||||
@@ -94,6 +94,40 @@ describe "polls tasks" do
|
|||||||
expect(Poll::Answer.count).to eq 2
|
expect(Poll::Answer.count).to eq 2
|
||||||
end
|
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
|
it "removes duplicate answers on tenants" do
|
||||||
create(:tenant, schema: "answers")
|
create(:tenant, schema: "answers")
|
||||||
|
|
||||||
@@ -176,6 +210,11 @@ describe "polls tasks" do
|
|||||||
user = create(:user, :level_two)
|
user = create(:user, :level_two)
|
||||||
question = create(:poll_question_multiple, :abc)
|
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 = {
|
answer_attributes = {
|
||||||
question_id: question.id,
|
question_id: question.id,
|
||||||
author_id: user.id,
|
author_id: user.id,
|
||||||
@@ -185,14 +224,23 @@ describe "polls tasks" do
|
|||||||
answer = create(:poll_answer, answer_attributes)
|
answer = create(:poll_answer, answer_attributes)
|
||||||
insert(: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
|
answer.reload
|
||||||
|
localized_answer.reload
|
||||||
|
|
||||||
expect(answer.option_id).to be nil
|
expect(answer.option_id).to be nil
|
||||||
|
expect(localized_answer.option_id).to be nil
|
||||||
|
|
||||||
Rake.application.invoke_task("polls:populate_option_id")
|
Rake.application.invoke_task("polls:populate_option_id")
|
||||||
answer.reload
|
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(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
|
end
|
||||||
|
|
||||||
it "populates the option_id column on tenants" do
|
it "populates the option_id column on tenants" do
|
||||||
|
|||||||
Reference in New Issue
Block a user