Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merging two/three records in rails

I want to merge two profiles into one. What is the best way to do this in Rails.

I have two profiles say user1 and user2 and there are at least 30 tables associated with them.

Now i want to merge them together so that there should be one profile say user1 and user2 should get deleted but all the associated data of user2 now should associate with user1.

For example: suppose user2 has two contacts and user1 has 3 contacts after merging user user1 should have 5 contacts.

like image 243
Salil Avatar asked Dec 26 '12 12:12

Salil


3 Answers

Something like this

@user1 = User.find(1);
@user2 = User.find(2);

Contact.where("user_id = ?", @user2.id).update_all(:user_id => @user1.id)
@user2.destroy

in case of generalize solution place file /lib/acts_as_user_merge.rb

module UserMerge
  module ActsAsUserMerge
    module Base
      def self.included(klass)
        klass.class_eval do
          extend Config
        end
      end
    end

    module Config
        def acts_as_user_merge
            include ::UserMerge::ActsAsUserMerge::InstanceMethods
        end
    end

    module InstanceMethods    
      def merge(user)
        models = Array.new
        models_names = User.reflections.collect{|a, b| b.class_name if b.macro==:has_many}.compact
        models_names.each do |name|
          models << Object.const_get name
        end
        models.each do |model|
          model.where("user_id = ?", user.id).update_all(:user_id => self.id)
        end
        user.destroy
      end
    end
  end
end

::ActiveRecord::Base.send :include, ::UserMerge::ActsAsUserMerge::Base

how to use

User < ActiveRecord::Base
  has_many ...

  acts_as_user_merge

end

@user1.merge(@user2)

kinda messy and not tested but should give you an idea

like image 190
Eugene Rourke Avatar answered Nov 01 '22 09:11

Eugene Rourke


Something like that

def merge_users(dead, user)
  User.reflections.each do |assoc, reflection|
    foreign_key = reflection.foreign_key
    case reflection.macro
    when :has_many, :has_one then
      unless reflection.options[:through]
        reflection.klass.where(foreign_key => dead.id).update_all(foreign_key => user.id) # if id is a primary key
      end
      if options[:as] # polymorphic
        if reflection.macro == :has_many
          dead.send("#{options[:as].pluralize}")).each { |r| user.send("#{options[:as].pluralize}<<", r) }
        else
          user.send("#{options[:as]}=", dead.send("#{options[:as]}"))
          user.save
        end
      end
    when :belongs_to then
      if options[:polymorphic]
        user.send("#{assoc}=", deaf.send(assoc))
        user.save
      else
        user.update_attribute(foreign_key, dead.send(foreign_key))
      end
    when :has_and_belongs_to_many then
      dead.send("#{assoc}")).each { |r| user.send("#{assoc}<<", r) }
    end

  end
end

merge_users(dead_user, user)
dead_user.destroy
like image 38
Valery Kvon Avatar answered Nov 01 '22 10:11

Valery Kvon


This article discusses this matter in depth, and provides the working code for it: http://ewout.name/2010/04/generic-deep-merge-for-activerecord/

like image 35
lulalala Avatar answered Nov 01 '22 09:11

lulalala