Added :synchronize_keys to the import options so importing can synchronize on fields beside the primary key.
https://github.com/zdennis/activerecord-import/issues/16
This commit is contained in:
parent
e00e9d7d59
commit
7958ed18c2
|
@ -212,7 +212,8 @@ class ActiveRecord::Base
|
||||||
end
|
end
|
||||||
|
|
||||||
if options[:synchronize]
|
if options[:synchronize]
|
||||||
synchronize( options[:synchronize] )
|
sync_keys = options[:synchronize_keys] || [self.primary_key]
|
||||||
|
synchronize( options[:synchronize], sync_keys)
|
||||||
end
|
end
|
||||||
|
|
||||||
return_obj.num_inserts = 0 if return_obj.num_inserts.nil?
|
return_obj.num_inserts = 0 if return_obj.num_inserts.nil?
|
||||||
|
|
|
@ -8,17 +8,29 @@ module ActiveRecord # :nodoc:
|
||||||
#
|
#
|
||||||
# This uses one query for all instance updates and then updates existing
|
# This uses one query for all instance updates and then updates existing
|
||||||
# instances rather sending one query for each instance
|
# 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?
|
return if instances.empty?
|
||||||
|
|
||||||
keys = instances.map(&"#{key}".to_sym)
|
conditions = {}
|
||||||
klass = instances.first.class
|
order = ""
|
||||||
fresh_instances = klass.find( :all, :conditions=>{ key=>keys }, :order=>"#{key} ASC" )
|
|
||||||
|
|
||||||
instances.each_with_index do |instance, index|
|
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_aggregation_cache
|
||||||
instance.clear_association_cache
|
instance.clear_association_cache
|
||||||
instance.instance_variable_set '@attributes', fresh_instances[index].attributes
|
instance.instance_variable_set '@attributes', matched_instance.attributes
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,26 @@ describe "#import" do
|
||||||
end
|
end
|
||||||
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
|
context "with an array of unsaved model instances" do
|
||||||
let(:topic) { Build(:topic, :title => "The RSpec Book", :author_name => "David Chelimsky")}
|
let(:topic) { Build(:topic, :title => "The RSpec Book", :author_name => "David Chelimsky")}
|
||||||
let(:topics) { Build(9, :topics) }
|
let(:topics) { Build(9, :topics) }
|
||||||
|
|
Loading…
Reference in a new issue