From: Robert Klemme Date: 2008-05-29T23:06:29+09:00 Subject: Re: Merge collections of objects 2008/5/29 John Butler : > Yes ive figured that out. Its proving a bit of pain especially with has > many through relationships. > > For the above i have a company that has many employees through > company_employees so what i basically want to do is. > > companyA has 2 employees "a", "b" > > companyB has 3 employees "a", "b", "c" > > Copy any employees from companyB that are not in companyA > Delete all reference to employees from companyB > > So > > companyA will have 3 employees "a", "b", "c" > > companyB will have no employees > > Ive tried various tings as there are a lot of associations i need to > copy over so im trying to create one method that will deal with this > passing through the 2 objects and the relationship in dyn_method: > > dyn_method = 'employees' > myarray = Array.new > myarray = companyA.send(dyn_method) | company_b.send(dyn_method) > companyA.send(dyn_method + '=',myarray) > > The below works as in it updates all the company_id links in the > company_employees table with companyA's id so the employees are only > linked to companyA and not referenced by companyB anymore. The > duplicates causes an issue here though. > dyn_method = 'company_employees' > companyA.send(dyn_method + '=',companyB.send(dyn_method)) > > Im still looking for the best solution for adding to a company which has > no employees and then to a company that already has employees but > ignoring the duplicates. Here is one way with a slightly different setting: I used a Struct generated class because that has attribute access similar to a Hash: Parameters are 1. the symbol of the relationship 2. the other instance 3. an optional list of key fields, if missing the object is the key irb(main):001:0> Company = Struct.new :rel_a, :rel_b do irb(main):002:1* def merge(rel, from, keys = nil) irb(main):003:2> from_r = from[rel] irb(main):004:2> return if from_r.nil? || from_r.empty? irb(main):005:2> irb(main):006:2* tmp = ((self[rel] || []) + from_r).inject({}) do |h,o| irb(main):007:3* k = keys ? keys.map {|k| o.send(k)} : o irb(main):008:3> h[k] ||= o irb(main):009:3> h irb(main):010:3> end irb(main):011:2> irb(main):012:2* self[rel] = tmp.values irb(main):013:2> from_r.clear irb(main):014:2> end irb(main):015:1> end => Company irb(main):016:0> c1 = Company.new [1,2,3] => # irb(main):017:0> c2 = Company.new [2,3,4] => # irb(main):018:0> c1.merge :rel_a, c2 => [] irb(main):019:0> c1 => # irb(main):020:0> c2 => # Now an example with key fields: irb(main):021:0> Person = Struct.new :id, :name => Person irb(main):022:0> c1 = Company.new [1,2,3].map {|i| Person.new i, "name #{i}"} => #, #, #], rel_b=nil> irb(main):023:0> c2 = Company.new [2,3,4].map {|i| Person.new i, "name #{i}"} => #, #, #], rel_b=nil> irb(main):024:0> c1.merge :rel_a, c2, [:id] => [] irb(main):025:0> c1 => #, #, #, #], rel_b=nil> irb(main):026:0> c2 => # irb(main):027:0> Kind regards robert -- use.inject do |as, often| as.you_can - without end