salesforce_ar_sync 2.0.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b19087f9160aa21606e6de401c9813e693fb306d
4
- data.tar.gz: 7bded65098335e5f1be42efa9bca7a8219c9e419
3
+ metadata.gz: f37d587db2ecda95601160de49a915cff74ca31a
4
+ data.tar.gz: e3451ccede1bcbe1a1ac6e59aa39241a0862f5cd
5
5
  SHA512:
6
- metadata.gz: 5a7d57027cd4067238f8992cfffda917b6dee7654cef6068e4e21c86f27f829fdb65e20e20497558581691165d4b1a02c814a989ba0c788ce310da3879f24b66
7
- data.tar.gz: 36219dd2e81e11afcfb77f73ba098c0f6dc427b9a9a7e764fa420c467eea15e2c5fc04877d79717119da6e0fad14675711e2a6dc37289d7ea0d2a59a75da3120
6
+ metadata.gz: 2fb081124bed9670b20b5485136dd1adbfedc7fd6b28db5438d1ddf0c1c11a04c96cb8a9f6dbf72b665c8f76b3c2fc853d1f57064840bd23c9d36babe44a8703
7
+ data.tar.gz: 6a3edd80c362394d93906a2888d8b9fb54fe4023c81c3a58dcb38efc3aac2edf094dfd9c3877178c71cb360875f1868224c1e23cca6d83acf82f82096914266f
data/README.md CHANGED
@@ -111,6 +111,7 @@ The options available to configure are
111
111
  * __organization_id__: the 18 character organization id of your Salesforce instance
112
112
  * __sync_enabled__: a global sync enabled flag which is a boolean true/false
113
113
  * __namespace_prefix__: Namespace prefix of your Salesforce app in case you specified one
114
+ * __deletion_map__: Salesforce object names mapped to internal app name.
114
115
 
115
116
  To generate a YAML file
116
117
 
@@ -125,6 +126,7 @@ which will create a template salesforce_ar_sync.yml in /config that looks like t
125
126
  organization_id: <organization id> #18 character organization_id
126
127
  sync_enabled: true
127
128
  namespace_prefix:
129
+ deletion_map:
128
130
 
129
131
 
130
132
  To use the ENV variable you must pass environemnt variables to rails via the _export_ command in bash or before the
@@ -134,6 +136,12 @@ initializer loads the ENV settings.
134
136
  $ export SALESFORCE_AR_SYNC_SYNC_ENABLED=true
135
137
  $ export SALESFORCE_AR_NAMESPACE_PREFIX=my_prefix
136
138
 
139
+ An example of adding an aliased object to the deletion map should look like the following:
140
+
141
+ deletion_map:
142
+ -
143
+ Account: 'YourModelName'
144
+
137
145
  ### Model Options
138
146
  The model can have several options set:
139
147
 
@@ -159,6 +167,8 @@ The model can have several options set:
159
167
 
160
168
  [__except__](#except)
161
169
 
170
+ [__unscoped_updates__](#unscoped_updates)
171
+
162
172
  #### <a id="salesforce_sync_enabled"></a>salesforce_sync_enabled
163
173
  Model level option to enable disable the sync, defaults to true.
164
174
 
@@ -246,6 +256,14 @@ method is given then only the salesforce_skip_sync attribute is used. Defaults t
246
256
  :except => :except_method_name
247
257
  ````
248
258
 
259
+ #### unscoped_updates
260
+ Enable bypassing the default scope when searching for records to update. This is useful when using a
261
+ soft deletion strategy that can respect SF undeletion.
262
+
263
+ ````ruby
264
+ :unscoped_updates => true
265
+ ````
266
+
249
267
  ### Stopping the Sync
250
268
 
251
269
  Stopping the gem from syncing can be done on three levels.
@@ -430,6 +448,16 @@ This is done using the :sync_outbound_delete option, which can take either a boo
430
448
  end
431
449
  ```
432
450
 
451
+ ### Soft Deletes
452
+ Setting unscoped_updates to true will permit you to find deleted objects to sync changes to. You can implement virtual attributes matching the
453
+ undelete field in SF to implement the soft deletion strategy of your choosing. For the paranoia gem:
454
+
455
+ ```ruby
456
+ def undeleted=(value)
457
+ restore if value
458
+ end
459
+ ```
460
+
433
461
  ## Errors
434
462
 
435
463
  ### Outbound Message Errors
@@ -1,7 +1,9 @@
1
1
  module SalesforceArSync
2
2
  class SoapMessageController < ::ApplicationController
3
+
4
+ protect_from_forgery with: :null_session
3
5
  before_filter :validate_ip_ranges
4
-
6
+
5
7
  def sync_object
6
8
  delayed_soap_handler SalesforceArSync::SoapHandler::Base
7
9
  end
@@ -4,17 +4,20 @@ production:
4
4
  # Salesforce owned IPs from: https://help.salesforce.com/apex/HTViewSolution?language=en_US&id=000003652
5
5
  ip_ranges: "204.14.232.0/23,204.14.237.0/24,96.43.144.0/22,96.43.148.0/22,204.14.234.0/23,204.14.238.0/23,182.50.76.0/22"
6
6
  namespace_prefix:
7
-
7
+ deletion_map:
8
+
8
9
  development:
9
10
  organization_id: <%= @organization_id %>
10
11
  sync_enabled: false
11
12
  # Salesforce owned IPs from: https://help.salesforce.com/apex/HTViewSolution?language=en_US&id=000003652
12
13
  ip_ranges: "204.14.232.0/23,204.14.237.0/24,96.43.144.0/22,96.43.148.0/22,204.14.234.0/23,204.14.238.0/23,182.50.76.0/22"
13
14
  namespace_prefix:
14
-
15
+ deletion_map:
16
+
15
17
  test:
16
18
  organization_id: <%= @organization_id %>
17
19
  sync_enabled: false
18
20
  # Salesforce owned IPs from: https://help.salesforce.com/apex/HTViewSolution?language=en_US&id=000003652
19
21
  ip_ranges: "204.14.232.0/23,204.14.237.0/24,96.43.144.0/22,96.43.148.0/22,204.14.234.0/23,204.14.238.0/23,182.50.76.0/22"
20
- namespace_prefix:
22
+ namespace_prefix:
23
+ deletion_map:
@@ -3,7 +3,7 @@ module SalesforceArSync
3
3
  initializer "salesforce_ar_sync.load_app_instance_data" do |app|
4
4
  SalesforceArSync.setup do |config|
5
5
  config.app_root = app.root
6
-
6
+
7
7
  #Load the configuration from the environment or a yaml file or disable it if no config present
8
8
  SalesforceArSync.config = Hash.new
9
9
  #load the config file if we have it
@@ -13,6 +13,7 @@ module SalesforceArSync
13
13
  SalesforceArSync.config["SYNC_ENABLED"] = config['sync_enabled']
14
14
  SalesforceArSync.config["IP_RANGES"] = config['ip_ranges'].split(',').map{ |ip| ip.strip }
15
15
  SalesforceArSync.config["NAMESPACE_PREFIX"] = config['namespace_prefix']
16
+ SalesforceArSync.config['DELETION_MAP'] = config['deletion_map'].stringify_keys
16
17
  end
17
18
 
18
19
  #if we have ENV flags prefer them
@@ -20,6 +21,7 @@ module SalesforceArSync
20
21
  SalesforceArSync.config["SYNC_ENABLED"] = ENV["SALESFORCE_AR_SYNC_SYNC_ENABLED"] if ENV.include? "SALESFORCE_AR_SYNC_SYNC_ENABLED"
21
22
  SalesforceArSync.config["IP_RANGES"] = ENV["SALESFORCE_AR_SYNC_IP_RANGES"].split(',').map{ |ip| ip.strip } if ENV["SALESFORCE_AR_SYNC_IP_RANGES"]
22
23
  SalesforceArSync.config["NAMESPACE_PREFIX"] = ENV["SALESFORCE_AR_NAMESPACE_PREFIX"] if ENV["SALESFORCE_AR_NAMESPACE_PREFIX"]
24
+ SalesforceArSync.config['DELETION_MAP'] = ENV['DELETION_MAP'] if ENV['DELETION_MAP']
23
25
 
24
26
  #do we have valid config options now?
25
27
  if !SalesforceArSync.config["ORGANIZATION_ID"].present? || SalesforceArSync.config["ORGANIZATION_ID"].length != 18
@@ -17,6 +17,7 @@ module SalesforceArSync
17
17
 
18
18
  self.sync_inbound_delete = options.has_key?(:sync_inbound_delete) ? options[:sync_inbound_delete] : true
19
19
  self.sync_outbound_delete = options.has_key?(:sync_outbound_delete) ? options[:sync_outbound_delete] : false
20
+ self.unscoped_updates = options.has_key?(:unscoped_updates) ? options[:unscoped_updates] : false
20
21
 
21
22
  self.salesforce_object_name_method = options.has_key?(:salesforce_object_name) ? options[:salesforce_object_name] : nil
22
23
  self.salesforce_skip_sync_method = options.has_key?(:except) ? options[:except] : nil
@@ -39,6 +39,9 @@ module SalesforceArSync
39
39
  attr_accessor :sync_inbound_delete
40
40
  attr_accessor :sync_outbound_delete
41
41
 
42
+ # Specify whether we should use an unscoped find to update an object (useful with paranoia gem to handle undeletes)
43
+ attr_accessor :unscoped_updates
44
+
42
45
  attr_accessor :salesforce_web_id_attribute_name
43
46
  attr_accessor :salesforce_sync_web_id
44
47
  attr_accessor :activerecord_web_id_attribute_name
@@ -56,12 +59,12 @@ module SalesforceArSync
56
59
  # Lastly it will create a new record setting it's salesforce_id
57
60
  def salesforce_update(attributes={})
58
61
  raise ArgumentError, "#{salesforce_id_attribute_name} parameter required" if attributes[salesforce_id_attribute_name].blank?
59
-
60
- object = self.find_by(salesforce_id: attributes[salesforce_id_attribute_name])
61
- object ||= self.find_by(activerecord_web_id_attribute_name => attributes[salesforce_web_id_attribute_name]) if salesforce_sync_web_id? && attributes[salesforce_web_id_attribute_name]
62
+ data_source = unscoped_updates ? unscoped : self
63
+ object = data_source.find_by(salesforce_id: attributes[salesforce_id_attribute_name])
64
+ 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]
62
65
 
63
66
  if object.nil?
64
- object = self.new
67
+ object = new
65
68
  salesforce_default_attributes_for_create.merge(:salesforce_id => attributes[salesforce_id_attribute_name]).each_pair do |k, v|
66
69
  object.send("#{k}=", v)
67
70
  end
@@ -34,9 +34,9 @@ module SalesforceArSync
34
34
 
35
35
  #xml for SFDC response
36
36
  #called from soap_message_controller
37
- def generate_response(error = nil)
37
+ def generate_response(error = nil)
38
38
  response = "<Ack>#{sobjects.nil? ? false : true}</Ack>" unless error
39
- if error
39
+ if error
40
40
  response = "<soapenv:Fault><faultcode>soap:Receiver</faultcode><faultstring>#{error.message}</faultstring></soapenv:Fault>"
41
41
  end
42
42
  return "<?xml version=\"1.0\" encoding=\"UTF-8\"?><soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><soapenv:Body><notificationsResponse>#{response}</notificationsResponse></soapenv:Body></soapenv:Envelope>"
@@ -45,11 +45,17 @@ module SalesforceArSync
45
45
  def self.namespaced(field)
46
46
  SalesforceArSync.config["NAMESPACE_PREFIX"].present? ? :"#{SalesforceArSync.config["NAMESPACE_PREFIX"]}__#{field}" : :"#{field}"
47
47
  end
48
-
48
+
49
+ # Get configuration for the in app deletions.
50
+ # Map to the object within the app if named differently then in SalesForce
51
+ def self.deletion_map(field)
52
+ SalesforceArSync.config['DELETION_MAP'].fetch(field, field)
53
+ end
54
+
49
55
  private
50
56
 
51
57
  def collect_sobjects
52
- notification = @xml_hashed["Envelope"]["Body"]["notifications"]["Notification"]
58
+ notification = @xml_hashed["Envelope"]["Body"]["notifications"]["Notification"]
53
59
  if notification.is_a? Array
54
60
  return notification.collect{ |h| h["sObject"].symbolize_keys}
55
61
  else
@@ -58,4 +64,4 @@ module SalesforceArSync
58
64
  end
59
65
  end
60
66
  end
61
- end
67
+ end
@@ -1,19 +1,21 @@
1
1
  module SalesforceArSync
2
2
  module SoapHandler
3
3
  class Delete < SalesforceArSync::SoapHandler::Base
4
- def process_notifications(priority = 90)
5
- batch_process do |sobject|
6
- SalesforceArSync::SoapHandler::Delete.delay(:priority => priority, :run_at => 5.seconds.from_now).delete_object(sobject)
7
- end
8
- end
4
+ def process_notifications(priority = 90)
5
+ batch_process do |sobject|
6
+ SalesforceArSync::SoapHandler::Delete.delay(priority: priority, run_at: 5.seconds.from_now).delete_object(sobject)
7
+ end
8
+ end
9
9
 
10
- def self.delete_object(hash = {})
11
- raise ArgumentError, "Object_Id__c parameter required" if hash[namespaced(:Object_Id__c)].blank?
12
- raise ArgumentError, "Object_Type__c parameter required" if hash[namespaced(:Object_Type__c)].blank?
13
-
14
- object = hash[namespaced(:Object_Type__c)].constantize.find_by_salesforce_id(hash[namespaced(:Object_Id__c)])
15
- object.destroy if object && object.ar_sync_inbound_delete?
16
- end
10
+ def self.delete_object(hash = {})
11
+ raise ArgumentError, 'Object_Id__c parameter required' if hash[namespaced(:Object_Id__c)].blank?
12
+ raise ArgumentError, 'Object_Type__c parameter required' if hash[namespaced(:Object_Type__c)].blank?
13
+ raise Exception, "Deletion failed: No class found for #{hash[namespaced(:Object_Type__c)]}" unless deletion_map(hash[namespaced(:Object_Type__c)]).safe_constantize
14
+
15
+ object = deletion_map(hash[namespaced(:Object_Type__c)]).safe_constantize.try(:find_by_salesforce_id, hash[namespaced(:Object_Id__c)])
16
+
17
+ object.destroy if object && object.ar_sync_inbound_delete?
18
+ end
17
19
  end
18
- end
19
- end
20
+ end
21
+ end
@@ -1,3 +1,3 @@
1
1
  module SalesforceArSync
2
- VERSION = "2.0.0"
2
+ VERSION = "2.0.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: salesforce_ar_sync
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Halliday
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2015-06-09 00:00:00.000000000 Z
15
+ date: 2016-04-18 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: rails
@@ -188,7 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
188
188
  version: '0'
189
189
  requirements: []
190
190
  rubyforge_project:
191
- rubygems_version: 2.4.7
191
+ rubygems_version: 2.5.1
192
192
  signing_key:
193
193
  specification_version: 4
194
194
  summary: ActiveRecord extension & rails engine for syncing data with Salesforce.com