Add task to delete duplicate voters

Note that, since poll answers belong to a user and not to a voter, we
aren't doing anything regarding poll answers. This is a separate topic
that might be dealt with in a separate pull request.

Also note that, since there are no records belonging to poll voters, and
poll voters don't use `acts_as_paranoia` and don't have any callbacks on
destroy, it doesn't really matter whether we call `destroy!` or
`delete`. We're using `delete` so there are no unintended side-effects
that might affect voters with the same `user_id` and `poll_id` on
Consul Democracy installations customizing this behavior.
This commit is contained in:
Javi Martín
2024-05-11 18:49:11 +02:00
parent 9a8bfac5bd
commit b013a5b1b6
3 changed files with 78 additions and 1 deletions

View File

@@ -7,6 +7,7 @@ namespace :consul do
desc "Runs tasks needed to upgrade from 2.1.1 to 2.2.0"
task "execute_release_2.2.0_tasks": [
"db:mask_ips"
"db:mask_ips",
"polls:remove_duplicate_voters"
]
end

27
lib/tasks/polls.rake Normal file
View File

@@ -0,0 +1,27 @@
namespace :polls do
desc "Removes duplicate poll voters"
task remove_duplicate_voters: :environment do
logger = ApplicationLogger.new
logger.info "Removing duplicate voters in polls"
Tenant.run_on_each do
duplicate_ids = Poll::Voter.select(:user_id, :poll_id)
.group(:user_id, :poll_id)
.having("count(*) > 1")
.pluck(:user_id, :poll_id)
duplicate_ids.each do |user_id, poll_id|
voters = Poll::Voter.where(user_id: user_id, poll_id: poll_id)
voters.excluding(voters.first).each do |voter|
voter.delete
tenant_info = " on tenant #{Tenant.current_schema}" unless Tenant.default?
logger.info "Deleted duplicate record with ID #{voter.id} " \
"from the #{Poll::Voter.table_name} table " \
"with user_id #{user_id} " \
"and poll_id #{poll_id}" + tenant_info.to_s
end
end
end
end
end

View File

@@ -0,0 +1,49 @@
require "rails_helper"
describe "polls tasks" do
let(:poll) { create(:poll) }
let(:user) { create(:user, :level_two) }
describe "polls:remove_duplicate_voters" do
before { Rake::Task["polls:remove_duplicate_voters"].reenable }
it "removes duplicate voters" do
second_user = create(:user, :level_two)
voter = create(:poll_voter, poll: poll, user: user)
second_voter = create(:poll_voter, poll: poll, user: second_user)
other_user_voter = create(:poll_voter, poll: poll, user: create(:user, :level_two))
other_poll_voter = create(:poll_voter, poll: create(:poll), user: user)
2.times { insert(:poll_voter, poll_id: poll.id, user_id: user.id) }
insert(:poll_voter, poll_id: poll.id, user_id: second_user.id)
expect(Poll::Voter.count).to eq 7
Rake.application.invoke_task("polls:remove_duplicate_voters")
expect(Poll::Voter.count).to eq 4
expect(Poll::Voter.all).to match_array [voter, second_voter, other_user_voter, other_poll_voter]
end
it "removes duplicate voters on tenants" do
create(:tenant, schema: "voters")
Tenant.switch("voters") do
poll = create(:poll)
user = create(:user, :level_two)
create(:poll_voter, poll: poll, user: user)
insert(:poll_voter, poll_id: poll.id, user_id: user.id)
expect(Poll::Voter.count).to eq 2
end
Rake.application.invoke_task("polls:remove_duplicate_voters")
Tenant.switch("voters") do
expect(Poll::Voter.count).to eq 1
end
end
end
end