diff --git a/lib/activerecord-import/import.rb b/lib/activerecord-import/import.rb index 31e9639..6270bc9 100644 --- a/lib/activerecord-import/import.rb +++ b/lib/activerecord-import/import.rb @@ -212,7 +212,8 @@ class ActiveRecord::Base end if options[:synchronize] - synchronize( options[:synchronize] ) + sync_keys = options[:synchronize_keys] || [self.primary_key] + synchronize( options[:synchronize], sync_keys) end return_obj.num_inserts = 0 if return_obj.num_inserts.nil? diff --git a/lib/activerecord-import/synchronize.rb b/lib/activerecord-import/synchronize.rb index c017ede..3f1554a 100644 --- a/lib/activerecord-import/synchronize.rb +++ b/lib/activerecord-import/synchronize.rb @@ -8,17 +8,29 @@ module ActiveRecord # :nodoc: # # This uses one query for all instance updates and then updates existing # instances rather sending one query for each instance - def self.synchronize(instances, key=self.primary_key) + def self.synchronize(instances, keys=[self.primary_key]) return if instances.empty? - - keys = instances.map(&"#{key}".to_sym) - klass = instances.first.class - fresh_instances = klass.find( :all, :conditions=>{ key=>keys }, :order=>"#{key} ASC" ) - instances.each_with_index do |instance, index| - instance.clear_aggregation_cache - instance.clear_association_cache - instance.instance_variable_set '@attributes', fresh_instances[index].attributes + conditions = {} + order = "" + + key_values = keys.map { |key| instances.map(&"#{key}".to_sym) } + keys.zip(key_values).each { |key, values| conditions[key] = values } + order = keys.map{ |key| "#{key} ASC" }.join(",") + + klass = instances.first.class + + fresh_instances = klass.find( :all, :conditions=>conditions, :order=>order ) + instances.each do |instance| + matched_instance = fresh_instances.detect do |fresh_instance| + keys.all?{ |key| fresh_instance.send(key) == instance.send(key) } + end + + if matched_instance + instance.clear_aggregation_cache + instance.clear_association_cache + instance.instance_variable_set '@attributes', matched_instance.attributes + end end end diff --git a/test/import_test.rb b/test/import_test.rb index 3c3fd5e..92ed3e7 100644 --- a/test/import_test.rb +++ b/test/import_test.rb @@ -66,6 +66,26 @@ describe "#import" do end end + context "with :synchronize option" do + context "synchronizing on new records" do + let(:new_topics) { Build(3, :topics) } + + it "doesn't reload any data (doesn't work)" do + Topic.import new_topics, :synchronize => new_topics + assert new_topics.all?(&:new_record?), "No record should have been reloaded" + end + end + + context "synchronizing on new records with explicit conditions" do + let(:new_topics) { Build(3, :topics) } + + it "reloads data for existing in-memory instances" do + Topic.import(new_topics, :synchronize => new_topics, :synchronize_key => [:title] ) + assert new_topics.all?(&:new_record?), "Records should have been reloaded" + end + end + end + context "with an array of unsaved model instances" do let(:topic) { Build(:topic, :title => "The RSpec Book", :author_name => "David Chelimsky")} let(:topics) { Build(9, :topics) }