app/models/merge_user.rb
class MergeUser
COLLECTIONS = [ :authentications, :comments, :events, :proposals, :votes ]
def initialize(email)
@email = email
end
def merge
return false if @email.blank?
users = User.where(email: @email)
return false if users.size <= 1
elect_a_profile users
transfer_avatars
merge_all_collections
destroy_extra_profiles
@elected_profile.user.save!
end
private
COLLECTIONS.each do |collection_merge_method|
define_method "merge_#{collection_merge_method}" do
merge_collection collection_merge_method
end
end
def extra_photo
@profiles_to_remove.map { |profile|
profile.user.photo? ? profile.user.photo : nil
}.compact.first
end
def transfer_avatars
user = @elected_profile.user
return if user.photo?
user.photo = extra_photo
end
def count_associations(profile)
profile.authentications.count +
profile.comments.count +
profile.events.count +
profile.proposals.count +
profile.votes.count
end
# Internal: find the user register with more relations, and return it.
def profile_with_more_associations(profiles)
profiles.sort { |p1, p2|
count_associations(p1) <=> count_associations(p2)
}.last
end
def elect_a_profile(users)
profiles = users.map { |user| Profile.new user }
@elected_profile = profile_with_more_associations profiles
profiles.delete @elected_profile
@profiles_to_remove = profiles
end
def merge_collection(collection_name)
into_collection = @elected_profile.public_send collection_name
@profiles_to_remove.each do |profile|
from_collection = profile.public_send collection_name
into_collection << from_collection
end
end
def destroy_extra_profiles
@profiles_to_remove.each do |profile|
profile.reload.destroy
end
end
def merge_all_collections
User.transaction do
COLLECTIONS.each { |collection| send "merge_#{collection}" }
end
end
end