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
|
||||
|
||||
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?
|
||||
|
|
|
@ -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" )
|
||||
conditions = {}
|
||||
order = ""
|
||||
|
||||
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_association_cache
|
||||
instance.instance_variable_set '@attributes', fresh_instances[index].attributes
|
||||
instance.instance_variable_set '@attributes', matched_instance.attributes
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -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) }
|
||||
|
|
Loading…
Reference in a new issue