Duplicate users occurr often enough that it is worthwhile. Can just be a task, but having a button on a user to merge them into another user (transferring all data from that user to the other user) would be nice.
Approximate code:
# Merges the source into the target user by changing all references to the source to the target, and then deletes the target.
# Fails if there is something umergeable.
def merge_user_into(source_user, target_user)
ActiveRecord::Base.transaction do
has_manies = [:team_membership, :staffing_jobs, :admin_staffing_debts, :admin_maintenance_debts, :membership_activation_tokens, :roles]
has_manies.each do |has_many_relation|
source_user.send(has_many_relation).each do |relation|
relation.update!(user: target_user)
end
end
# Has One's
if source_user.membership_card.present?
raise(ActiveRecord::AttributeAssignmentError, "The source and target user both have a Membership Card attached. Please delete one and try merging again.") if target_user.membership_card.present?
target_user.membership_card = source_user.membership_card
end
if source_user.marketing_creatives_profile.present?
raise(ActiveRecord::AttributeAssignmentError, "The source and target user both have a Marketing Creatives Profile attached. Please delete one and try merging again.") if target_user.marketing_creatives_profile.present?
target_user.marketing_creatives_profile = source_user.marketing_creatives_profile
end
if source_user.avatar.attached? && !target_user.avatar.attached?
source_user.avatar.blob.open do |tempfile|
target_user.avatar.attach(
io: tempfile,
filename: source_user.avatar.filename,
content_type: source_user.avatar.content_type
)
end
end
single_fields = [:phone_number, :first_name, :last_name, :bio]
single_fields.each do |single_field|
target_user[single_field] ||= source_user[single_field]
end
target_user.public_profile = false unless source_user.public_profile
target_user.sign_in_count += source_user.sign_in_count
target_user.save!
# TODO: This raise is broken, which means the others likely are too.
#raise(ActiveRecord::AttributeAssignmentError, "test")
# Reload changes to the has_many relations and such ..
source_user.reload
# and try to destroy the old user.
begin
source_user.destroy!
rescue ActiveRecord::RecordNotDestroyed => e
# TODO: This is untested. Can potentially be tested by commenting out the source_user.reload bit a few lines above.
raise(e, e.message + "; Messages: #{source_user.errors}")
end
end
end
Duplicate users occurr often enough that it is worthwhile. Can just be a task, but having a button on a user to merge them into another user (transferring all data from that user to the other user) would be nice.
Approximate code: