salesforce_ar_sync 2.0.0 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
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