Reassigning an ActiveRecord instance and associated foreign keys

There is a way in Rails / ActiveReocrd to replace one instance with another so that all relations / foreign keys are resolved.

I could imagine something like this:

//setup customer1 = Customer.find(1) customer2 = Customer.find(2) //this would be cool customer1.replace_with(customer2) 

Suppose client1 is poorly configured, and someone left and created customer2 without knowing about client1, it would be nice to be able to quickly install everything for client 2

Thus, you will also need to update any foreign keys, as well as

User belongs_to: client Website belongs_to: client

then any users / websites with the foreign key customer_id = 1 will automatically get the value 2 using this "replace_with" method

Is there such a thing?

[I can imagine a hack involving Customer.reflect_on_all_associations (: has_many), etc.]

Cheers j

+4
source share
1 answer

Something like this may work, although there may be a more correct way:

Updated . Fixed several errors in the example associations.

 class MyModel < ActiveRecord::Base ... # if needed, force logout / expire session in controller beforehand. def replace_with (another_record) # handles attributes and belongs_to associations attribute_hash = another_record.attributes attribute_hash.delete('id') self.update_attributes!(attribute_hash) ### Begin association example, not complete. # generic way of finding model constants find_model_proc = Proc.new{ |x| x.to_s.singularize.camelize.constantize } model_constant = find_model_proc.call(self.class.name) # handle :has_one, :has_many associations have_ones = model_constant.reflect_on_all_associations(:has_one).find_all{|i| !i.options.include?(:through)} have_manys = model_constant.reflect_on_all_associations(:has_many).find_all{|i| !i.options.include?(:through)} update_assoc_proc = Proc.new do |assoc, associated_record, id| primary_key = assoc.primary_key_name.to_sym attribs = associated_record.attributes attribs[primary_key] = self.id associated_record.update_attributes!(attribs) end have_ones.each do |assoc| associated_record = self.send(assoc.name) unless associated_record.nil? update_assoc_proc.call(assoc, associated_record, self.id) end end have_manys.each do |assoc| associated_records = self.send(assoc.name) associated_records.each do |associated_record| update_assoc_proc.call(assoc, associated_record, self.id) end end ### End association example, not complete. # and if desired.. # do not call :destroy if you have any associations set with :dependents => :destroy another_record.destroy end ... end 

I included an example of how you can handle some associations, but overall it can get complicated.

+1
source

All Articles