diff --git a/app/workers/migrate_data_to_work_field_worker.rb b/app/workers/migrate_data_to_work_field_worker.rb new file mode 100644 index 000000000..bb0e8a5e2 --- /dev/null +++ b/app/workers/migrate_data_to_work_field_worker.rb @@ -0,0 +1,20 @@ +# NOTE: this worker is only used inside a DUS. Once that ran across the fleet +# and we gave self-hosters some time to run it to we should be able to remove +# this. +class MigrateDataToWorkFieldWorker + include Sidekiq::Worker + + def perform(profile_id) + profile = Profile.find_by(id: profile_id) + return unless profile + + work_info = profile.employment_title + work_info << " at #{profile.employer_name}" if profile.employer_name.present? + + # NOTE: This worker is only concerned with updating "work", an unvalidated + # key in the JSONB data object. We don't want this to fail, even if e.g. + # a newly added validation makes the record invalid. + profile.data[:work] = work_info + profile.save(validate: false) + end +end diff --git a/lib/data_update_scripts/20210630034523_add_work_profile_field.rb b/lib/data_update_scripts/20210630034523_add_work_profile_field.rb new file mode 100644 index 000000000..c5745be33 --- /dev/null +++ b/lib/data_update_scripts/20210630034523_add_work_profile_field.rb @@ -0,0 +1,12 @@ +module DataUpdateScripts + class AddWorkProfileField + def run + ProfileField.find_or_create_by( + label: "Work", + placeholder_text: "What do you do? Example: CEO at ACME Inc.", + input_type: :text_field, + display_area: :header, + ) + end + end +end diff --git a/lib/data_update_scripts/20210630041322_migrate_data_to_work_field.rb b/lib/data_update_scripts/20210630041322_migrate_data_to_work_field.rb new file mode 100644 index 000000000..d24b91d74 --- /dev/null +++ b/lib/data_update_scripts/20210630041322_migrate_data_to_work_field.rb @@ -0,0 +1,19 @@ +module DataUpdateScripts + class MigrateDataToWorkField + # NOTE: data->>'employment_title' <> '' takes care of both null and empty strings. + # This works for two reasons: + # 1. We use the JSONB ->> operator, which coerces the result to text. This also + # turns JSONB `null` into "Postgres" `null`. + # See: https://www.postgresql.org/docs/13/functions-json.html + # 2. `null` is neither equal to nor unequal to any string. For this reason + # `stringexpression <> ''` can be used to filter both `null`s and empty strings. + # See: https://stackoverflow.com/questions/23766084/best-way-to-check-for-empty-or-null-value + QUERY = "data->>'employment_title' <> '' AND data->>'work' IS NULL".freeze + + def run + Profile.where(QUERY).select(:id).find_each do |profile| + MigrateDataToWorkFieldWorker.perform_async(profile.id) + end + end + end +end diff --git a/spec/lib/data_update_scripts/add_work_profile_field_spec.rb b/spec/lib/data_update_scripts/add_work_profile_field_spec.rb new file mode 100644 index 000000000..5fe21f6b4 --- /dev/null +++ b/spec/lib/data_update_scripts/add_work_profile_field_spec.rb @@ -0,0 +1,10 @@ +require "rails_helper" +require Rails.root.join( + "lib/data_update_scripts/20210630034523_add_work_profile_field.rb", +) + +describe DataUpdateScripts::AddWorkProfileField do + it "adds a new profile field" do + expect { described_class.new.run }.to change(ProfileField, :count).by(1) + end +end diff --git a/spec/lib/data_update_scripts/migrate_data_to_work_field_spec.rb b/spec/lib/data_update_scripts/migrate_data_to_work_field_spec.rb new file mode 100644 index 000000000..55c15e506 --- /dev/null +++ b/spec/lib/data_update_scripts/migrate_data_to_work_field_spec.rb @@ -0,0 +1,37 @@ +require "rails_helper" +require Rails.root.join( + "lib/data_update_scripts/20210630041322_migrate_data_to_work_field.rb", +) + +describe DataUpdateScripts::MigrateDataToWorkField, sidekiq: :inline do + let!(:user) { create(:user) } + let(:profile) { user.profile } + + before do + ProfileField.find_or_create_by!(label: "Work", input_type: :text_field) + Profile.refresh_attributes! + end + + it "migrates employment titles without employer name" do + profile.update!(employment_title: "Tester") + expect { described_class.new.run } + .to change { profile.reload.work }.from(nil).to("Tester") + end + + it "migrates employment titles and employer name" do + profile.update!(employment_title: "Tester", employer_name: "ACME Inc.") + expect { described_class.new.run } + .to change { profile.reload.work }.from(nil).to("Tester at ACME Inc.") + end + + it "ignores blank employment titles" do + profile.update!(employment_title: "", employer_name: "ACME Inc.") + expect { described_class.new.run }.not_to change { profile.reload.work } + end + + it "ignores blank employer names" do + profile.update!(employment_title: "Tester", employer_name: "") + expect { described_class.new.run } + .to change { profile.reload.work }.from(nil).to("Tester") + end +end