From bc05ec1050e12558602be5c86d6a21675689fb8f Mon Sep 17 00:00:00 2001 From: James Smith Date: Wed, 12 Sep 2018 13:12:57 -0400 Subject: [PATCH] [LG-588] Rake task populating email addresses **Why**: We want to support multiple email addresses per account. This requires that we store email addresses in their own table. **How**: A rake task to copy existing email information to the new table. --- .../populate_email_addresses_table.rb | 39 +++++++++++++++ lib/tasks/migrate_email_addresses.rake | 7 +++ .../populate_email_addresses_table_spec.rb | 49 +++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 app/services/populate_email_addresses_table.rb create mode 100644 lib/tasks/migrate_email_addresses.rake create mode 100644 spec/services/populate_email_addresses_table_spec.rb diff --git a/app/services/populate_email_addresses_table.rb b/app/services/populate_email_addresses_table.rb new file mode 100644 index 00000000000..069be4bbdab --- /dev/null +++ b/app/services/populate_email_addresses_table.rb @@ -0,0 +1,39 @@ +class PopulateEmailAddressesTable + def initialize + @count = 0 + @total = 0 + end + + # :reek:DuplicateMethodCall + def call + User.in_batches(of: 1000) do |relation| + sleep(1) + process_batch(relation) + Rails.logger.info "#{@count} / #{@total}" + end + Rails.logger.info "Processed #{@count} user email addresses" + end + + private + + def process_batch(relation) + User.transaction do + relation.each do |user| + @total += 1 + next if user.email_address.present? || user.encrypted_email.blank? + user.create_email_address(email_info_for_user(user)) + @count += 1 + end + end + end + + def email_info_for_user(user) + { + encrypted_email: user.encrypted_email, + email_fingerprint: user.email_fingerprint, + confirmed_at: user.confirmed_at, + confirmation_sent_at: user.confirmation_sent_at, + confirmation_token: user.confirmation_token, + } + end +end diff --git a/lib/tasks/migrate_email_addresses.rake b/lib/tasks/migrate_email_addresses.rake new file mode 100644 index 00000000000..0d669df442f --- /dev/null +++ b/lib/tasks/migrate_email_addresses.rake @@ -0,0 +1,7 @@ +namespace :adhoc do + desc 'Copy email addresses to the new table' + task populate_email_addresses: :environment do + Rails.logger = Logger.new(STDOUT) + PopulateEmailAddressesTable.new.call + end +end diff --git a/spec/services/populate_email_addresses_table_spec.rb b/spec/services/populate_email_addresses_table_spec.rb new file mode 100644 index 00000000000..10fe5e0abe5 --- /dev/null +++ b/spec/services/populate_email_addresses_table_spec.rb @@ -0,0 +1,49 @@ +require 'rails_helper' + +describe PopulateEmailAddressesTable do + let(:subject) { described_class.new } + + describe '#call' do + context 'a user with no email' do + let!(:user) { create(:user, email: '', confirmed_at: nil) } + + it 'migrates nothing' do + expect(user.email_address).to be_nil + + expect { subject.call }.to change { EmailAddress.count }.by(0) + end + end + + context 'a user with an email' do + let!(:user) { create(:user) } + + context 'and no email_address entry' do + before(:each) do + user.email_address.delete + user.reload + end + + it 'migrates without decrypting and re-encrypting' do + expect(EncryptedAttribute).to_not receive(:new) + subject.call + end + + it 'migrates the email' do + expect { subject.call }.to change { EmailAddress.count }.by(1) + + address = user.reload.email_address + expect(user.email).to eq address.email + expect(user.confirmed_at).to eq user.confirmed_at + expect(user.confirmation_sent_at).to eq user.confirmation_sent_at + expect(user.confirmation_token).to eq user.confirmation_token + end + end + + context 'and an existing email_address entry' do + it 'adds no new rows' do + expect { subject.call }.to change { EmailAddress.count }.by(0) + end + end + end + end +end