Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions lib/salesforce_ar_sync/salesforce_sync.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,24 +71,42 @@ module ClassMethods
def salesforce_update(attributes = {})
raise ArgumentError, "#{salesforce_id_attribute_name} parameter required" if attributes[salesforce_id_attribute_name].blank?

retried = false
begin
object = find_record(attributes) || build_record(attributes)

object.salesforce_process_update(attributes) if object && (object.salesforce_updated_at.nil? || (object.salesforce_updated_at && object.salesforce_updated_at < Time.parse(attributes[:SystemModstamp])))
rescue ActiveRecord::RecordNotUnique
if retried
raise
else
retried = true
retry
end
end
end

def find_record(attributes)
data_source = unscoped_updates ? unscoped : self
object = data_source.find_by(salesforce_id: attributes[salesforce_id_attribute_name])
object ||= data_source.find_by(activerecord_web_id_attribute_name => attributes[salesforce_web_id_attribute_name]) if salesforce_sync_web_id? && attributes[salesforce_web_id_attribute_name]
return object if object.present?

if !object && additional_lookup_fields
if additional_lookup_fields
additional_lookup_fields.each do |attribute_name, salesforce_attribute_name|
object = data_source.find_by(attribute_name => attributes[salesforce_attribute_name]) if attributes[salesforce_attribute_name]
break if object
end
return object
end
end

if object.nil?
object = new
def build_record(attributes)
new.tap do |object|
salesforce_default_attributes_for_create.merge(salesforce_id: attributes[salesforce_id_attribute_name]).each_pair do |k, v|
object.send("#{k}=", v)
end
end

object.salesforce_process_update(attributes) if object && (object.salesforce_updated_at.nil? || (object.salesforce_updated_at && object.salesforce_updated_at < Time.parse(attributes[:SystemModstamp])))
end
end

Expand Down
28 changes: 28 additions & 0 deletions spec/salesforce_ar_sync/salesforce_ar_sync_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,34 @@ class TestSyncable < ActiveRecord::Base

Contact.salesforce_update(Id: sf_id)
end

context 'when an existing record is not found but ActiveRecord::RecordNotUnique is raised on save' do
let(:contact) do
Contact.new(
first_name: 'Bob',
last_name: 'Smith',
phone: '519 555-1212',
email: 'bsmith@example.com',
salesforce_skip_sync: true
)
end
let(:return_values) { [:raise, true] }

before do
allow(Contact).to receive(:salesforce_sync_web_id?).and_return(false)
allow(Contact).to receive(:unscoped_updates?).and_return(false)
# simulate the record being created after the find but before the save
allow(Contact).to receive(:new).and_return(contact)
allow(contact).to receive(:save!).exactly(2).times do
return_value = return_values.shift
return_value == :raise ? (contact.save and raise(ActiveRecord::RecordNotUnique)) : return_value
end
end
it 'retries and updates the found record' do
expect(Contact).to receive(:new).once
expect { Contact.salesforce_update(Id: 321, WebId__c: 432) }.not_to raise_exception
end
end
end

describe '.salesforce_id_attribute_name' do
Expand Down