salesforce_ar_sync 1.1.2 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +99 -56
- data/lib/generators/salesforce_ar_sync/migrations/migrations_generator.rb +2 -2
- data/lib/salesforce_ar_sync/extenders/salesforce_syncable.rb +12 -7
- data/lib/salesforce_ar_sync/railtie.rb +7 -0
- data/lib/salesforce_ar_sync/salesforce_sync.rb +68 -31
- data/lib/salesforce_ar_sync/soap_handler/delete.rb +1 -1
- data/lib/salesforce_ar_sync/version.rb +1 -1
- data/lib/salesforce_ar_sync.rb +2 -1
- metadata +45 -64
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b19087f9160aa21606e6de401c9813e693fb306d
|
4
|
+
data.tar.gz: 7bded65098335e5f1be42efa9bca7a8219c9e419
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5a7d57027cd4067238f8992cfffda917b6dee7654cef6068e4e21c86f27f829fdb65e20e20497558581691165d4b1a02c814a989ba0c788ce310da3879f24b66
|
7
|
+
data.tar.gz: 36219dd2e81e11afcfb77f73ba098c0f6dc427b9a9a7e764fa420c467eea15e2c5fc04877d79717119da6e0fad14675711e2a6dc37289d7ea0d2a59a75da3120
|
data/README.md
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# SalesforceArSync
|
2
2
|
|
3
|
-
SalesforceARSync allows you to sync models and fields with Salesforce through a combination of
|
3
|
+
SalesforceARSync allows you to sync models and fields with Salesforce through a combination of
|
4
4
|
Outbound Messaging, SOAP and databasedotcom.
|
5
5
|
|
6
6
|
## Installation
|
7
7
|
|
8
8
|
### Requirements
|
9
9
|
|
10
|
-
* Rails
|
10
|
+
* Rails ~> 4.0
|
11
11
|
* Salesforce.com instance
|
12
12
|
* [Have your 18 character organization id ready](#finding-your-18-character-organization-id)
|
13
13
|
* databasedotcom gem >= 1.3 installed and configured [see below](#databasedotcom)
|
@@ -15,32 +15,32 @@ Outbound Messaging, SOAP and databasedotcom.
|
|
15
15
|
|
16
16
|
### Salesforce Setup
|
17
17
|
|
18
|
-
Before you can start syncing your data several things must be completed in Salesforce.
|
18
|
+
Before you can start syncing your data several things must be completed in Salesforce.
|
19
19
|
|
20
20
|
#### 1. Setup Remote Access
|
21
|
-
Create a new Remote Access Application entry by going to
|
21
|
+
Create a new Remote Access Application entry by going to
|
22
22
|
|
23
23
|
Setup -> Develop -> Remote Access
|
24
|
-
|
24
|
+
|
25
25
|
You can use http://localhost/nothing for the _Callback URL_
|
26
26
|
|
27
27
|
#### 2. Setup Outbound Messaging
|
28
|
-
Each model you wish to sync requires a workflow to trigger outbound messaging. You can set the worflow
|
29
|
-
to trigger on the specific fields you wish to update.
|
28
|
+
Each model you wish to sync requires a workflow to trigger outbound messaging. You can set the worflow
|
29
|
+
to trigger on the specific fields you wish to update.
|
30
30
|
|
31
31
|
Setup -> Create -> Workflow & Approvals -> Worflow Rules
|
32
|
-
|
33
|
-
Click _New Rule_, select the object (model) you wish to sync and click _Next_, give the rule a name, select
|
34
|
-
_Every time a record is created or edited_ and set a rule on the field(s) you want to sync ( a formula checking
|
32
|
+
|
33
|
+
Click _New Rule_, select the object (model) you wish to sync and click _Next_, give the rule a name, select
|
34
|
+
_Every time a record is created or edited_ and set a rule on the field(s) you want to sync ( a formula checking
|
35
35
|
if the fields have changed is recommended). Click _Save & Next_, in the _Add Worflow Action_ dropdown select
|
36
|
-
_New Outbound Message_. Enter a name and set the _Endpoint URL_ to be http://yoursite.com/integration/sf_soap/model_name.
|
37
|
-
Select the fields you wish to sync (Id and SystemModstamp are required).
|
36
|
+
_New Outbound Message_. Enter a name and set the _Endpoint URL_ to be http://yoursite.com/integration/sf_soap/model_name.
|
37
|
+
Select the fields you wish to sync (Id and SystemModstamp are required).
|
38
38
|
|
39
39
|
*You need to do this for each object/model you want to sync.
|
40
40
|
|
41
41
|
### databasedotcom
|
42
42
|
|
43
|
-
Before using the salesforce_ar_sync gem you must ensure you have the databasedotcom gem installed and configured
|
43
|
+
Before using the salesforce_ar_sync gem you must ensure you have the databasedotcom gem installed and configured
|
44
44
|
properly. Make sure each of the models you wish to sync are materialized.
|
45
45
|
|
46
46
|
````ruby
|
@@ -65,17 +65,17 @@ And then execute:
|
|
65
65
|
Or install it yourself as:
|
66
66
|
|
67
67
|
$ gem install salesforce_ar_sync
|
68
|
-
|
68
|
+
|
69
69
|
### Application Setup
|
70
70
|
|
71
|
-
Before using the gem you must complete the setup of your rails app.
|
71
|
+
Before using the gem you must complete the setup of your rails app.
|
72
72
|
|
73
73
|
The gem needs to know your 18 character organization id, it can be stored in a YAML file or in the ENV class.
|
74
74
|
|
75
75
|
To create the yaml file run
|
76
76
|
|
77
77
|
$ rails generate salesforce_ar_sync:configuration <organization id>
|
78
|
-
|
78
|
+
|
79
79
|
Next you will need to decide which models you want to sync. For each model you must create a migration and run them
|
80
80
|
|
81
81
|
$ rails generate salesforce_ar_sync:migrations <models> --migrate
|
@@ -87,7 +87,7 @@ To mount the engine add the following line to your routes.rb file
|
|
87
87
|
You can change '/integration' to whatever you want, all of the engine routes will be based off of this path. Running
|
88
88
|
|
89
89
|
$ rake routes | grep salesforce_ar_sync
|
90
|
-
|
90
|
+
|
91
91
|
will show you all of the gems routes, make sure you point your outbound messages at these urls.
|
92
92
|
|
93
93
|
Next you will need to tell the gem which models are syncable by adding _salesforce_syncable_ to your model class
|
@@ -97,7 +97,7 @@ and specifying which attributes you would like to sync.
|
|
97
97
|
salesforce_syncable :sync_attributes => {:FirstName => :first_name, :LastName => :last_name}
|
98
98
|
````
|
99
99
|
|
100
|
-
The first parameter in the _:sync_attributes_ hash is the Salesforce field name and the second is the model attribute
|
100
|
+
The first parameter in the _:sync_attributes_ hash is the Salesforce field name and the second is the model attribute
|
101
101
|
name.
|
102
102
|
|
103
103
|
## Usage
|
@@ -115,18 +115,18 @@ The options available to configure are
|
|
115
115
|
To generate a YAML file
|
116
116
|
|
117
117
|
$ rails generate salesforce_ar_sync:configuration
|
118
|
-
|
118
|
+
|
119
119
|
Or with an organization id
|
120
|
-
|
120
|
+
|
121
121
|
$ rails generate salesforce_ar_sync:configuration 123456789123456789
|
122
|
-
|
122
|
+
|
123
123
|
which will create a template salesforce_ar_sync.yml in /config that looks like the following
|
124
124
|
|
125
125
|
organization_id: <organization id> #18 character organization_id
|
126
126
|
sync_enabled: true
|
127
127
|
namespace_prefix:
|
128
128
|
|
129
|
-
|
129
|
+
|
130
130
|
To use the ENV variable you must pass environemnt variables to rails via the _export_ command in bash or before the
|
131
131
|
initializer loads the ENV settings.
|
132
132
|
|
@@ -137,16 +137,27 @@ initializer loads the ENV settings.
|
|
137
137
|
### Model Options
|
138
138
|
The model can have several options set:
|
139
139
|
|
140
|
-
[__salesforce_sync_enabled__](#salesforce_sync_enabled)
|
141
|
-
|
142
|
-
[
|
143
|
-
|
144
|
-
[
|
145
|
-
|
146
|
-
[
|
147
|
-
|
148
|
-
[
|
149
|
-
|
140
|
+
[__salesforce_sync_enabled__](#salesforce_sync_enabled)
|
141
|
+
|
142
|
+
[__sync_attributes__](#sync_attributes)
|
143
|
+
|
144
|
+
[__async_attributes__](#async_attributes)
|
145
|
+
|
146
|
+
[__default_attributes_for_create__](#default_attributes_for_create)
|
147
|
+
|
148
|
+
[__salesforce_id_attribute_name__](#salesforce_id_attribute_name)
|
149
|
+
|
150
|
+
[__web_id_attribute_name__](#web_id_attribute_name)
|
151
|
+
|
152
|
+
[__activerecord_web_id_attribute_name__](#activerecord_web_id_attribute_name)
|
153
|
+
|
154
|
+
[__salesforce_sync_web_id__](#salesforce_sync_web_id)
|
155
|
+
|
156
|
+
[__web_class_name__](#web_class_name)
|
157
|
+
|
158
|
+
[__salesforce_object_name__](#salesforce_object_name)
|
159
|
+
|
160
|
+
[__except__](#except)
|
150
161
|
|
151
162
|
#### <a id="salesforce_sync_enabled"></a>salesforce_sync_enabled
|
152
163
|
Model level option to enable disable the sync, defaults to true.
|
@@ -154,11 +165,11 @@ Model level option to enable disable the sync, defaults to true.
|
|
154
165
|
````ruby
|
155
166
|
:salesforce_sync_enabled => false
|
156
167
|
````
|
157
|
-
|
168
|
+
|
158
169
|
#### sync_attributes
|
159
|
-
Hash mapping of Salesforce attributes to web attributes, defaults to empty hash.
|
160
|
-
"Web" attributes can be actual method names to return a custom value.If you are providing a method name to return a
|
161
|
-
value, you should also implement a corresponding my_method_changed? to return if the value has changed. Otherwise
|
170
|
+
Hash mapping of Salesforce attributes to web attributes, defaults to empty hash.
|
171
|
+
"Web" attributes can be actual method names to return a custom value.If you are providing a method name to return a
|
172
|
+
value, you should also implement a corresponding my_method_changed? to return if the value has changed. Otherwise
|
162
173
|
it will always be synced.
|
163
174
|
|
164
175
|
````ruby
|
@@ -166,16 +177,16 @@ it will always be synced.
|
|
166
177
|
````
|
167
178
|
|
168
179
|
#### async_attributes
|
169
|
-
An array of Salesforce attributes which should be synced asynchronously, defaults to an empty array. When an object is saved and only attributes contained in this array, the save to Salesforce will be queued and processed asyncronously.
|
180
|
+
An array of Salesforce attributes which should be synced asynchronously, defaults to an empty array. When an object is saved and only attributes contained in this array, the save to Salesforce will be queued and processed asyncronously.
|
170
181
|
Use this carefully, nothing is done to ensure data integrity, if multiple jobs are queued for a single object there is no way to guarentee that they are processed in order, or that the save to Salesforce will succeed.
|
171
182
|
|
172
183
|
````ruby
|
173
184
|
:async_attributes => ["Last_Login__c", "Login_Count__c"]
|
174
185
|
````
|
175
186
|
|
176
|
-
Note: The model will fall back to synchronous sync if non-synchronous attributes are changed along with async
|
187
|
+
Note: The model will fall back to synchronous sync if non-synchronous attributes are changed along with async
|
177
188
|
attributes
|
178
|
-
|
189
|
+
|
179
190
|
#### default_attributes_for_create
|
180
191
|
A hash of default attributes that should be used when we are creating a new record, defaults to empty hash.
|
181
192
|
|
@@ -197,6 +208,13 @@ The field name of the web id attribute in the Salesforce Object, defaults to _We
|
|
197
208
|
:web_id_attribute_name => :WebId__c
|
198
209
|
````
|
199
210
|
|
211
|
+
#### activerecord_web_id_attribute_name
|
212
|
+
The field name of the web id attribute in the Active Record Object, defaults to id
|
213
|
+
|
214
|
+
````ruby
|
215
|
+
:activerecord_web_id_attribute_name => :id
|
216
|
+
````
|
217
|
+
|
200
218
|
#### salesforce_sync_web_id
|
201
219
|
Enable or disable sync of the web id, defaults to false. Use this if you have a need for the id field of the ActiveRecord model to by synced to Salesforce.
|
202
220
|
|
@@ -205,10 +223,10 @@ Enable or disable sync of the web id, defaults to false. Use this if you have a
|
|
205
223
|
````
|
206
224
|
|
207
225
|
#### web_class_name
|
208
|
-
The name of the Web Objects class. A custom value can be provided if you wish to sync to a SF object and back to a
|
209
|
-
different web object. Defaults to the model name. This would generally be used if you wanted to flatten a web object
|
226
|
+
The name of the Web Objects class. A custom value can be provided if you wish to sync to a SF object and back to a
|
227
|
+
different web object. Defaults to the model name. This would generally be used if you wanted to flatten a web object
|
210
228
|
into a larger SF object like Contact.
|
211
|
-
|
229
|
+
|
212
230
|
````ruby
|
213
231
|
:web_class_name => 'Contact',
|
214
232
|
````
|
@@ -221,7 +239,7 @@ Optionally holds the name of a method which will return the name of the Salesfor
|
|
221
239
|
````
|
222
240
|
|
223
241
|
#### except
|
224
|
-
Optionally holds the name of a method which can contain logic to determine if a record should be synced on save. If no
|
242
|
+
Optionally holds the name of a method which can contain logic to determine if a record should be synced on save. If no
|
225
243
|
method is given then only the salesforce_skip_sync attribute is used. Defaults to nil.
|
226
244
|
|
227
245
|
````ruby
|
@@ -230,9 +248,9 @@ method is given then only the salesforce_skip_sync attribute is used. Defaults t
|
|
230
248
|
|
231
249
|
### Stopping the Sync
|
232
250
|
|
233
|
-
Stopping the gem from syncing can be done on three levels.
|
251
|
+
Stopping the gem from syncing can be done on three levels.
|
234
252
|
|
235
|
-
* The global level before the app starts via the .yml file, ENV variables or after the app starts with the gem's
|
253
|
+
* The global level before the app starts via the .yml file, ENV variables or after the app starts with the gem's
|
236
254
|
configuration variable _SALESFORCE_AR_SYNC_CONFIG["SYNC_ENABLED"]_
|
237
255
|
* The model level by setting the _:salesforce_sync_enabled => false_ or _:except => :method_name_
|
238
256
|
* The instance level by setting _:salesforce_skip_sync => true_ in the instance
|
@@ -254,7 +272,7 @@ end
|
|
254
272
|
class Contact < ActiveRecord::Base
|
255
273
|
attributes :first_name, :last_name, :phone, :email, :last_login_time, :salesforce_id, :salesforce_updated_at
|
256
274
|
attr_accessor :first_name, :last_name, :phone, :email
|
257
|
-
|
275
|
+
|
258
276
|
salesforce_syncable :sync_attributes => {:FirstName => :first_name, :LastName => :last_name, :Phone => :phone, :Email => :email}
|
259
277
|
end
|
260
278
|
```
|
@@ -265,7 +283,7 @@ end
|
|
265
283
|
class Contact < ActiveRecord::Base
|
266
284
|
attributes :first_name, :last_name, :phone, :email, :last_login_time, :salesforce_id, :salesforce_updated_at
|
267
285
|
attr_accessor :first_name, :last_name, :phone, :email
|
268
|
-
|
286
|
+
|
269
287
|
salesforce_syncable :sync_attributes => {:FirstName => :first_name, :LastName => :last_name, :Phone => :phone, :Email => :email},
|
270
288
|
:salesforce_sync_enabled => false
|
271
289
|
end
|
@@ -277,10 +295,10 @@ end
|
|
277
295
|
class Contact < ActiveRecord::Base
|
278
296
|
attributes :first_name, :last_name, :phone, :email, :last_login_time, :salesforce_id, :salesforce_updated_at
|
279
297
|
attr_accessor :first_name, :last_name, :phone, :email
|
280
|
-
|
298
|
+
|
281
299
|
salesforce_syncable :sync_attributes => {:FirstName => :first_name, :LastName => :last_name, :Phone => :phone, :Email => :email},
|
282
300
|
:except => :skip_sync?
|
283
|
-
|
301
|
+
|
284
302
|
def skip_sync?
|
285
303
|
if first_name.blank?
|
286
304
|
return true
|
@@ -302,7 +320,7 @@ customer.salesforce_skip_sync = true
|
|
302
320
|
class Contact < ActiveRecord::Base
|
303
321
|
attributes :first_name, :last_name, :phone, :email, :last_login_time, :salesforce_id, :salesforce_updated_at
|
304
322
|
attr_accessor :first_name, :last_name, :phone, :email, :last_login_time
|
305
|
-
|
323
|
+
|
306
324
|
salesforce_syncable :sync_attributes => {:FirstName => :first_name, :LastName => :last_name, :Phone => :phone, :Email => :email, :Last_Login_Time__c => :last_login_time},
|
307
325
|
:async_attributes => ["Last_Login_Time__c"]
|
308
326
|
end
|
@@ -314,7 +332,7 @@ end
|
|
314
332
|
class Contact < ActiveRecord::Base
|
315
333
|
attributes :first_name, :last_name, :phone, :email, :last_login_time, :salesforce_id, :salesforce_updated_at
|
316
334
|
attr_accessor :first_name, :last_name, :phone, :email, :last_login_time
|
317
|
-
|
335
|
+
|
318
336
|
salesforce_syncable :sync_attributes => {:FirstName => :first_name, :LastName => :last_name, :Phone => :phone, :Email => :email},
|
319
337
|
:default_attributes_for_create => {:password_change_required => true}
|
320
338
|
end
|
@@ -348,11 +366,11 @@ using the 18 digit Salesforce id, but maintain our ActiveRecord relationships.
|
|
348
366
|
end
|
349
367
|
|
350
368
|
def salesforce_account_id=(account_id)
|
351
|
-
self.account = nil
|
369
|
+
self.account = nil if account_id.nil? and return
|
352
370
|
self.account = Account.find_or_create_by_salesforce_id(account_id)
|
353
371
|
end
|
354
372
|
end
|
355
|
-
|
373
|
+
|
356
374
|
```
|
357
375
|
|
358
376
|
### Defining a Custom Salesforce Object
|
@@ -361,7 +379,7 @@ using the 18 digit Salesforce id, but maintain our ActiveRecord relationships.
|
|
361
379
|
class Contact < ActiveRecord::Base
|
362
380
|
attributes :first_name, :last_name, :phone, :email, :last_login_time, :salesforce_id, :salesforce_updated_at
|
363
381
|
attr_accessor :first_name, :last_name, :phone, :email, :last_login_time
|
364
|
-
|
382
|
+
|
365
383
|
salesforce_syncable :sync_attributes => {:FirstName => :first_name, :LastName => :last_name, :Phone => :phone, :Email => :email},
|
366
384
|
:salesforce_object_name => :custom_salesforce_object_name
|
367
385
|
|
@@ -372,6 +390,7 @@ end
|
|
372
390
|
```
|
373
391
|
|
374
392
|
## Deletes
|
393
|
+
### Inbound Deletes
|
375
394
|
In order to handle the delete of objects coming from Salesforce, a bit of code is necessary because an Outbound Message cannot be triggered when
|
376
395
|
an object is deleted. To work around this you will need to create a new Custom Object in your Salesforce environment:
|
377
396
|
|
@@ -387,6 +406,30 @@ Object_Type__c will hold the name of the Rails Model that the Salesforce object
|
|
387
406
|
If you trigger a record to be written to this object whenever another object is deleted, and configure an Outbound Message to send to the /sf_soap/delete action
|
388
407
|
whenever a Deleted_Object__c record is created, the corresponding record will be removed from your Rails app.
|
389
408
|
|
409
|
+
Syncing inbound deletes is enabled by default, but can be configured in the Rails Model.
|
410
|
+
This is done using the :sync_inbound_delete option, which can take either a boolean value, or the name of a method that returns a boolean value.
|
411
|
+
|
412
|
+
```ruby
|
413
|
+
salesforce_syncable :sync_inbound_delete => :inbound_delete
|
414
|
+
#:sync_inbound_delete => true
|
415
|
+
def inbound_delete
|
416
|
+
return self.comments.count == 0
|
417
|
+
end
|
418
|
+
```
|
419
|
+
|
420
|
+
### Outbound Deletes
|
421
|
+
Syncing outbound deletes to Salesforce is disabled by default, but can be configured in the Rails Model.
|
422
|
+
This is done using the :sync_outbound_delete option, which can take either a boolean value, or the name of a method that returns a boolean value.
|
423
|
+
|
424
|
+
```ruby
|
425
|
+
salesforce_syncable :sync_outbound_delete => :outbound_delete
|
426
|
+
#:sync_outbound_delete => false
|
427
|
+
|
428
|
+
def outbound_delete
|
429
|
+
return self.is_trial_user?
|
430
|
+
end
|
431
|
+
```
|
432
|
+
|
390
433
|
## Errors
|
391
434
|
|
392
435
|
### Outbound Message Errors
|
@@ -396,8 +439,8 @@ If the SOAP handler encounters an error it will be recorded in the log of the ou
|
|
396
439
|
Setup -> Monitoring -> Outbound Messages
|
397
440
|
|
398
441
|
## <a id="orga_id"></a>Finding your 18 Character Organization ID
|
399
|
-
Your 15 character organization id can be found in _Setup -> Company Profile -> Company Information_. You must convert
|
400
|
-
it to an 18 character id by running it through the tool located here:
|
442
|
+
Your 15 character organization id can be found in _Setup -> Company Profile -> Company Information_. You must convert
|
443
|
+
it to an 18 character id by running it through the tool located here:
|
401
444
|
http://cloudjedi.wordpress.com/no-fuss-salesforce-id-converter/ or by installing the Force.com Utility Belt for Chrome.
|
402
445
|
|
403
446
|
## Contributing
|
@@ -17,7 +17,7 @@ module SalesforceArSync
|
|
17
17
|
|
18
18
|
def create_migrations
|
19
19
|
models.each do |model|
|
20
|
-
|
20
|
+
create_ar_sync_migration(model)
|
21
21
|
end
|
22
22
|
|
23
23
|
if options[:migrate] == "yes"
|
@@ -41,7 +41,7 @@ module SalesforceArSync
|
|
41
41
|
@prev_migration_nr.to_s
|
42
42
|
end
|
43
43
|
|
44
|
-
def
|
44
|
+
def create_ar_sync_migration(model_name)
|
45
45
|
#we can't load all the models in so let's assume it follows the standard nameing convention
|
46
46
|
@table_name = model_name.tableize
|
47
47
|
@model_name = model_name
|
@@ -1,6 +1,6 @@
|
|
1
1
|
module SalesforceArSync
|
2
2
|
module Extenders
|
3
|
-
module SalesforceSyncable
|
3
|
+
module SalesforceSyncable
|
4
4
|
def salesforce_syncable(options = {})
|
5
5
|
require 'salesforce_ar_sync/salesforce_sync'
|
6
6
|
include SalesforceArSync::SalesforceSync
|
@@ -11,21 +11,26 @@ module SalesforceArSync
|
|
11
11
|
self.salesforce_default_attributes_for_create = options.has_key?(:default_attributes_for_create) ? options[:default_attributes_for_create] : {}
|
12
12
|
self.salesforce_id_attribute_name = options.has_key?(:salesforce_id_attribute_name) ? options[:salesforce_id_attribute_name] : :Id
|
13
13
|
self.salesforce_web_id_attribute_name = options.has_key?(:web_id_attribute_name) ? options[:web_id_attribute_name] : :WebId__c
|
14
|
+
self.activerecord_web_id_attribute_name = options.has_key?(:activerecord_web_id_attribute_name) ? options[:activerecord_web_id_attribute_name] : :id
|
14
15
|
self.salesforce_sync_web_id = options.has_key?(:salesforce_sync_web_id) ? options[:salesforce_sync_web_id] : false
|
15
16
|
self.salesforce_web_class_name = options.has_key?(:web_class_name) ? options[:web_class_name] : self.name
|
16
|
-
|
17
|
+
|
18
|
+
self.sync_inbound_delete = options.has_key?(:sync_inbound_delete) ? options[:sync_inbound_delete] : true
|
19
|
+
self.sync_outbound_delete = options.has_key?(:sync_outbound_delete) ? options[:sync_outbound_delete] : false
|
20
|
+
|
17
21
|
self.salesforce_object_name_method = options.has_key?(:salesforce_object_name) ? options[:salesforce_object_name] : nil
|
18
22
|
self.salesforce_skip_sync_method = options.has_key?(:except) ? options[:except] : nil
|
19
|
-
|
23
|
+
|
20
24
|
instance_eval do
|
21
25
|
before_save :salesforce_sync
|
22
26
|
after_create :sync_web_id
|
23
|
-
|
27
|
+
after_commit :salesforce_delete_object, on: :destroy
|
28
|
+
|
24
29
|
def salesforce_sync_web_id?
|
25
30
|
self.salesforce_sync_web_id
|
26
31
|
end
|
27
32
|
end
|
28
|
-
|
33
|
+
|
29
34
|
class_eval do
|
30
35
|
# Calls a method if provided to return the name of the Salesforce object the model is syncing to.
|
31
36
|
# If no method is provided, defaults to the class name
|
@@ -33,8 +38,8 @@ module SalesforceArSync
|
|
33
38
|
return send(self.class.salesforce_object_name_method) if self.class.salesforce_object_name_method.present?
|
34
39
|
return self.class.name
|
35
40
|
end
|
36
|
-
|
37
|
-
# Calls a method, if provided, to determine if a record should be synced to Salesforce.
|
41
|
+
|
42
|
+
# Calls a method, if provided, to determine if a record should be synced to Salesforce.
|
38
43
|
# The salesforce_skip_sync instance variable is also used.
|
39
44
|
# The SALESFORCE_AR_SYNC_ENABLED flag overrides all the others if set to false
|
40
45
|
def salesforce_skip_sync?
|
@@ -1,11 +1,11 @@
|
|
1
1
|
require 'active_support/concern'
|
2
2
|
|
3
3
|
module SalesforceArSync
|
4
|
-
module SalesforceSync
|
4
|
+
module SalesforceSync
|
5
5
|
extend ActiveSupport::Concern
|
6
|
-
|
7
|
-
module ClassMethods
|
8
|
-
# Optionally holds the value to determine if salesforce syncing is enabled. Defaults to true. If set
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
# Optionally holds the value to determine if salesforce syncing is enabled. Defaults to true. If set
|
9
9
|
# to false syncing will be disabled for the class
|
10
10
|
attr_accessor :salesforce_sync_enabled
|
11
11
|
|
@@ -14,15 +14,15 @@ module SalesforceArSync
|
|
14
14
|
# { :Email => :login, :FirstName => :first_name, :LastName => :last_name }
|
15
15
|
#
|
16
16
|
# "Web" attributes can be actual method names to return a custom value
|
17
|
-
# If you are providing a method name to return a value, you should also implement a corresponding my_method_changed? to
|
17
|
+
# If you are providing a method name to return a value, you should also implement a corresponding my_method_changed? to
|
18
18
|
# return if the value has changed. Otherwise it will always be synced.
|
19
19
|
attr_accessor :salesforce_sync_attribute_mapping
|
20
|
-
|
20
|
+
|
21
21
|
# Returns an array of Salesforce attributes which should be synced asynchronously
|
22
22
|
# Example: ["Last_Login_Date__c", "Login_Count__c" ]
|
23
23
|
# Note: The model will fall back to synchronous sync if non-synchronous attributes are changed along with async attributes
|
24
24
|
attr_accessor :salesforce_async_attributes
|
25
|
-
|
25
|
+
|
26
26
|
# Returns a hash of default attributes that should be used when we are creating a new record
|
27
27
|
attr_accessor :salesforce_default_attributes_for_create
|
28
28
|
|
@@ -31,19 +31,25 @@ module SalesforceArSync
|
|
31
31
|
|
32
32
|
# Returns the name of the Web Objects class. A custom value can be provided if you wish
|
33
33
|
# to sync to a SF object and back to a different web object. This would generally be used
|
34
|
-
# if you wanted to flatten a web object into a larger SF object like Contact
|
34
|
+
# if you wanted to flatten a web object into a larger SF object like Contact
|
35
35
|
attr_accessor :salesforce_web_class_name
|
36
36
|
|
37
|
-
|
37
|
+
# Specify whether or not we sync deletes inbound from salesforce or outbound from this app
|
38
|
+
# Accepts either a true/false or a symbol to a method to be called
|
39
|
+
attr_accessor :sync_inbound_delete
|
40
|
+
attr_accessor :sync_outbound_delete
|
41
|
+
|
42
|
+
attr_accessor :salesforce_web_id_attribute_name
|
38
43
|
attr_accessor :salesforce_sync_web_id
|
39
|
-
|
44
|
+
attr_accessor :activerecord_web_id_attribute_name
|
45
|
+
|
40
46
|
# Optionally holds the name of a method which will return the name of the Salesforce object to sync to
|
41
47
|
attr_accessor :salesforce_object_name_method
|
42
48
|
|
43
49
|
# Optionally holds the name of a method which can contain logic to determine if a record should be synced on save.
|
44
50
|
# If no method is given then only the salesforce_skip_sync attribute is used.
|
45
51
|
attr_accessor :salesforce_skip_sync_method
|
46
|
-
|
52
|
+
|
47
53
|
# Accepts values from an outbound message hash and will either update an existing record OR create a new record
|
48
54
|
# Firstly attempts to find an object by the salesforce_id attribute
|
49
55
|
# Secondly attempts to look an object up by it's ID (WebId__c in outbound message)
|
@@ -51,9 +57,9 @@ module SalesforceArSync
|
|
51
57
|
def salesforce_update(attributes={})
|
52
58
|
raise ArgumentError, "#{salesforce_id_attribute_name} parameter required" if attributes[salesforce_id_attribute_name].blank?
|
53
59
|
|
54
|
-
object = self.
|
55
|
-
object ||= self.
|
56
|
-
|
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
|
+
|
57
63
|
if object.nil?
|
58
64
|
object = self.new
|
59
65
|
salesforce_default_attributes_for_create.merge(:salesforce_id => attributes[salesforce_id_attribute_name]).each_pair do |k, v|
|
@@ -68,7 +74,7 @@ module SalesforceArSync
|
|
68
74
|
# if this instance variable is set to true, the salesforce_sync method will return without attempting
|
69
75
|
# to sync data to Salesforce
|
70
76
|
attr_accessor :salesforce_skip_sync
|
71
|
-
|
77
|
+
|
72
78
|
# Salesforce completely excludes any empty/null fields from Outbound Messages
|
73
79
|
# We initialize all declared attributes as nil before mapping the values from the message
|
74
80
|
def salesforce_empty_attributes
|
@@ -81,8 +87,8 @@ module SalesforceArSync
|
|
81
87
|
|
82
88
|
# An internal method used to get a hash of values that we are going to set from a Salesforce outbound message hash
|
83
89
|
def salesforce_attributes_to_set(attributes = {})
|
84
|
-
{}.tap do |hash|
|
85
|
-
# loop through the hash of attributes from the outbound message, and compare to our sf mappings and
|
90
|
+
{}.tap do |hash|
|
91
|
+
# loop through the hash of attributes from the outbound message, and compare to our sf mappings and
|
86
92
|
# create a reversed hash of value's and key's to pass to update_attributes
|
87
93
|
attributes.each do |key, value|
|
88
94
|
# make sure our sync_mapping contains the salesforce attribute AND that our object has a setter for it
|
@@ -106,9 +112,9 @@ module SalesforceArSync
|
|
106
112
|
attributes_to_update.each_pair do |k, v|
|
107
113
|
self.send("#{k}=", v)
|
108
114
|
end
|
109
|
-
|
115
|
+
|
110
116
|
# we don't want to keep going in a endless loop. SF has just updated these values.
|
111
|
-
self.salesforce_skip_sync = true
|
117
|
+
self.salesforce_skip_sync = true
|
112
118
|
self.save!
|
113
119
|
end
|
114
120
|
|
@@ -116,12 +122,12 @@ module SalesforceArSync
|
|
116
122
|
# return salesforce_object_exists_method if respond_to? salesforce_exists_method
|
117
123
|
# return salesforce_object_exists_default
|
118
124
|
# end
|
119
|
-
|
120
|
-
|
125
|
+
|
126
|
+
|
121
127
|
# Finds a salesforce record by its Id and returns nil or its SystemModstamp
|
122
128
|
def system_mod_stamp
|
123
129
|
hash = JSON.parse(SF_CLIENT.http_get("/services/data/v#{SF_CLIENT.version}/query", :q => "SELECT SystemModstamp FROM #{salesforce_object_name} WHERE Id = '#{salesforce_id}'").body)
|
124
|
-
hash["records"].first.try(:[], "SystemModstamp")
|
130
|
+
hash["records"].first.try(:[], "SystemModstamp")
|
125
131
|
end
|
126
132
|
|
127
133
|
|
@@ -137,7 +143,7 @@ module SalesforceArSync
|
|
137
143
|
|
138
144
|
# create a hash of updates to send to salesforce
|
139
145
|
def salesforce_attributes_to_update(include_all = false)
|
140
|
-
{}.tap do |hash|
|
146
|
+
{}.tap do |hash|
|
141
147
|
self.class.salesforce_sync_attribute_mapping.each do |key, value|
|
142
148
|
if self.respond_to?(value)
|
143
149
|
|
@@ -150,7 +156,7 @@ module SalesforceArSync
|
|
150
156
|
hash[key] = attribute_value if include_all || salesforce_should_update_attribute?(value)
|
151
157
|
end
|
152
158
|
end
|
153
|
-
end
|
159
|
+
end
|
154
160
|
end
|
155
161
|
|
156
162
|
def is_boolean?(attribute)
|
@@ -159,17 +165,33 @@ module SalesforceArSync
|
|
159
165
|
|
160
166
|
def salesforce_create_object(attributes)
|
161
167
|
attributes.merge!(self.class.salesforce_web_id_attribute_name.to_s => id) if self.class.salesforce_sync_web_id? && !new_record?
|
162
|
-
result = SF_CLIENT.http_post("/services/data/v#{SF_CLIENT.version}/sobjects/#{salesforce_object_name}", attributes.to_json)
|
168
|
+
result = SF_CLIENT.http_post("/services/data/v#{SF_CLIENT.version}/sobjects/#{salesforce_object_name}", format_attributes(attributes).to_json)
|
163
169
|
self.salesforce_id = JSON.parse(result.body)["id"]
|
164
170
|
@exists_in_salesforce = true
|
165
171
|
end
|
166
172
|
|
167
173
|
def salesforce_update_object(attributes)
|
168
174
|
attributes.merge!(self.class.salesforce_web_id_attribute_name.to_s => id) if self.class.salesforce_sync_web_id? && !new_record?
|
169
|
-
SF_CLIENT.http_patch("/services/data/v#{SF_CLIENT.version}/sobjects/#{salesforce_object_name}/#{salesforce_id}", attributes.to_json)
|
175
|
+
SF_CLIENT.http_patch("/services/data/v#{SF_CLIENT.version}/sobjects/#{salesforce_object_name}/#{salesforce_id}", format_attributes(attributes).to_json)
|
170
176
|
end
|
171
177
|
|
172
|
-
|
178
|
+
def salesforce_delete_object
|
179
|
+
if self.ar_sync_outbound_delete?
|
180
|
+
SF_CLIENT.http_delete("/services/data/v#{SF_CLIENT.version}/sobjects/#{salesforce_object_name}/#{salesforce_id}")
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
# Check to see if the user passed in a true/false, if so return that, if not then they passed int a symbol to a method
|
185
|
+
# We then call the method and use its value instead
|
186
|
+
def ar_sync_inbound_delete?
|
187
|
+
[true,false].include?(self.class.sync_inbound_delete) ? self.class.sync_inbound_delete : send(self.class.sync_inbound_delete)
|
188
|
+
end
|
189
|
+
|
190
|
+
def ar_sync_outbound_delete?
|
191
|
+
[true,false].include?(self.class.sync_outbound_delete) ? self.class.sync_outbound_delete : send(self.class.sync_outbound_delete)
|
192
|
+
end
|
193
|
+
|
194
|
+
# if attributes specified in the async_attributes array are the only attributes being modified, then sync the data
|
173
195
|
# via delayed_job
|
174
196
|
def salesforce_perform_async_call?
|
175
197
|
return false if salesforce_attributes_to_update.empty? || self.class.salesforce_async_attributes.empty?
|
@@ -185,18 +207,33 @@ module SalesforceArSync
|
|
185
207
|
if salesforce_object_exists?
|
186
208
|
salesforce_update_object(salesforce_attributes_to_update) if salesforce_attributes_to_update.present?
|
187
209
|
else
|
188
|
-
salesforce_create_object(salesforce_attributes_to_update(!new_record?)) if salesforce_id.nil?
|
210
|
+
salesforce_create_object(salesforce_attributes_to_update(!new_record?)) if salesforce_id.nil?
|
189
211
|
end
|
190
212
|
end
|
191
213
|
rescue Exception => ex
|
192
214
|
self.errors[:base] << ex.message
|
193
215
|
return false
|
194
216
|
end
|
195
|
-
|
196
|
-
def sync_web_id
|
217
|
+
|
218
|
+
def sync_web_id
|
197
219
|
return false if !self.class.salesforce_sync_web_id? || self.salesforce_skip_sync?
|
198
|
-
SF_CLIENT.http_patch("/services/data/v#{SF_CLIENT.version}/sobjects/#{salesforce_object_name}/#{salesforce_id}", { self.class.salesforce_web_id_attribute_name.to_s =>
|
220
|
+
SF_CLIENT.http_patch("/services/data/v#{SF_CLIENT.version}/sobjects/#{salesforce_object_name}/#{salesforce_id}", { self.class.salesforce_web_id_attribute_name.to_s => get_activerecord_web_id }.to_json) if salesforce_id
|
221
|
+
end
|
222
|
+
|
223
|
+
def get_activerecord_web_id
|
224
|
+
self.send(self.class.activerecord_web_id_attribute_name)
|
199
225
|
end
|
200
226
|
|
227
|
+
private
|
228
|
+
|
229
|
+
# Multi-picklists in the SF Rest API are expected to be in a semicolon separated list
|
230
|
+
# This method converts all attribute that are arrays into these values
|
231
|
+
# Eg. ["A","B","C"] => "A;B;C"
|
232
|
+
def format_attributes(attributes)
|
233
|
+
attributes.each do |k,v|
|
234
|
+
attributes[k] = v.join(";") if v.is_a?(Array)
|
235
|
+
end
|
236
|
+
return attributes
|
237
|
+
end
|
201
238
|
end
|
202
239
|
end
|
@@ -12,7 +12,7 @@ module SalesforceArSync
|
|
12
12
|
raise ArgumentError, "Object_Type__c parameter required" if hash[namespaced(:Object_Type__c)].blank?
|
13
13
|
|
14
14
|
object = hash[namespaced(:Object_Type__c)].constantize.find_by_salesforce_id(hash[namespaced(:Object_Id__c)])
|
15
|
-
object.destroy if object
|
15
|
+
object.destroy if object && object.ar_sync_inbound_delete?
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
data/lib/salesforce_ar_sync.rb
CHANGED
@@ -5,11 +5,12 @@ require 'salesforce_ar_sync/salesforce_object_sync'
|
|
5
5
|
require 'salesforce_ar_sync/soap_handler/base'
|
6
6
|
require 'salesforce_ar_sync/soap_handler/delete'
|
7
7
|
require 'salesforce_ar_sync/ip_constraint'
|
8
|
+
require 'salesforce_ar_sync/railtie'
|
8
9
|
|
9
10
|
module SalesforceArSync
|
10
11
|
mattr_accessor :app_root
|
11
12
|
mattr_accessor :config
|
12
|
-
|
13
|
+
|
13
14
|
def self.setup
|
14
15
|
yield self
|
15
16
|
end
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: salesforce_ar_sync
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
5
|
-
prerelease:
|
4
|
+
version: 2.0.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Michael Halliday
|
@@ -13,150 +12,132 @@ authors:
|
|
13
12
|
autorequire:
|
14
13
|
bindir: bin
|
15
14
|
cert_chain: []
|
16
|
-
date:
|
15
|
+
date: 2015-06-09 00:00:00.000000000 Z
|
17
16
|
dependencies:
|
18
17
|
- !ruby/object:Gem::Dependency
|
19
18
|
name: rails
|
20
19
|
requirement: !ruby/object:Gem::Requirement
|
21
|
-
none: false
|
22
20
|
requirements:
|
23
|
-
- -
|
21
|
+
- - "~>"
|
24
22
|
- !ruby/object:Gem::Version
|
25
|
-
version:
|
23
|
+
version: '4.0'
|
26
24
|
type: :runtime
|
27
25
|
prerelease: false
|
28
26
|
version_requirements: !ruby/object:Gem::Requirement
|
29
|
-
none: false
|
30
27
|
requirements:
|
31
|
-
- -
|
28
|
+
- - "~>"
|
32
29
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
30
|
+
version: '4.0'
|
34
31
|
- !ruby/object:Gem::Dependency
|
35
|
-
name:
|
32
|
+
name: actionpack-xml_parser
|
36
33
|
requirement: !ruby/object:Gem::Requirement
|
37
|
-
none: false
|
38
34
|
requirements:
|
39
|
-
- -
|
35
|
+
- - ">="
|
40
36
|
- !ruby/object:Gem::Version
|
41
37
|
version: '0'
|
42
|
-
type: :
|
38
|
+
type: :runtime
|
43
39
|
prerelease: false
|
44
40
|
version_requirements: !ruby/object:Gem::Requirement
|
45
|
-
none: false
|
46
41
|
requirements:
|
47
|
-
- -
|
42
|
+
- - ">="
|
48
43
|
- !ruby/object:Gem::Version
|
49
44
|
version: '0'
|
50
45
|
- !ruby/object:Gem::Dependency
|
51
|
-
name:
|
46
|
+
name: rake
|
52
47
|
requirement: !ruby/object:Gem::Requirement
|
53
|
-
none: false
|
54
48
|
requirements:
|
55
|
-
- -
|
49
|
+
- - ">="
|
56
50
|
- !ruby/object:Gem::Version
|
57
51
|
version: '0'
|
58
52
|
type: :development
|
59
53
|
prerelease: false
|
60
54
|
version_requirements: !ruby/object:Gem::Requirement
|
61
|
-
none: false
|
62
55
|
requirements:
|
63
|
-
- -
|
56
|
+
- - ">="
|
64
57
|
- !ruby/object:Gem::Version
|
65
58
|
version: '0'
|
66
59
|
- !ruby/object:Gem::Dependency
|
67
|
-
name:
|
60
|
+
name: rspec
|
68
61
|
requirement: !ruby/object:Gem::Requirement
|
69
|
-
none: false
|
70
62
|
requirements:
|
71
|
-
- -
|
63
|
+
- - ">="
|
72
64
|
- !ruby/object:Gem::Version
|
73
65
|
version: '0'
|
74
66
|
type: :development
|
75
67
|
prerelease: false
|
76
68
|
version_requirements: !ruby/object:Gem::Requirement
|
77
|
-
none: false
|
78
69
|
requirements:
|
79
|
-
- -
|
70
|
+
- - ">="
|
80
71
|
- !ruby/object:Gem::Version
|
81
72
|
version: '0'
|
82
73
|
- !ruby/object:Gem::Dependency
|
83
|
-
name:
|
74
|
+
name: webmock
|
84
75
|
requirement: !ruby/object:Gem::Requirement
|
85
|
-
none: false
|
86
76
|
requirements:
|
87
|
-
- -
|
77
|
+
- - ">="
|
88
78
|
- !ruby/object:Gem::Version
|
89
79
|
version: '0'
|
90
80
|
type: :development
|
91
81
|
prerelease: false
|
92
82
|
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
none: false
|
94
83
|
requirements:
|
95
|
-
- -
|
84
|
+
- - ">="
|
96
85
|
- !ruby/object:Gem::Version
|
97
86
|
version: '0'
|
98
87
|
- !ruby/object:Gem::Dependency
|
99
|
-
name:
|
88
|
+
name: vcr
|
100
89
|
requirement: !ruby/object:Gem::Requirement
|
101
|
-
none: false
|
102
90
|
requirements:
|
103
|
-
- -
|
91
|
+
- - ">="
|
104
92
|
- !ruby/object:Gem::Version
|
105
|
-
version: 0
|
93
|
+
version: '0'
|
106
94
|
type: :development
|
107
95
|
prerelease: false
|
108
96
|
version_requirements: !ruby/object:Gem::Requirement
|
109
|
-
none: false
|
110
97
|
requirements:
|
111
|
-
- -
|
98
|
+
- - ">="
|
112
99
|
- !ruby/object:Gem::Version
|
113
|
-
version: 0
|
100
|
+
version: '0'
|
114
101
|
- !ruby/object:Gem::Dependency
|
115
|
-
name:
|
102
|
+
name: ammeter
|
116
103
|
requirement: !ruby/object:Gem::Requirement
|
117
|
-
none: false
|
118
104
|
requirements:
|
119
|
-
- -
|
105
|
+
- - "~>"
|
120
106
|
- !ruby/object:Gem::Version
|
121
|
-
version:
|
107
|
+
version: 1.1.2
|
122
108
|
type: :development
|
123
109
|
prerelease: false
|
124
110
|
version_requirements: !ruby/object:Gem::Requirement
|
125
|
-
none: false
|
126
111
|
requirements:
|
127
|
-
- -
|
112
|
+
- - "~>"
|
128
113
|
- !ruby/object:Gem::Version
|
129
|
-
version:
|
114
|
+
version: 1.1.2
|
130
115
|
- !ruby/object:Gem::Dependency
|
131
|
-
name:
|
116
|
+
name: sqlite3
|
132
117
|
requirement: !ruby/object:Gem::Requirement
|
133
|
-
none: false
|
134
118
|
requirements:
|
135
|
-
- -
|
119
|
+
- - ">="
|
136
120
|
- !ruby/object:Gem::Version
|
137
121
|
version: '0'
|
138
122
|
type: :development
|
139
123
|
prerelease: false
|
140
124
|
version_requirements: !ruby/object:Gem::Requirement
|
141
|
-
none: false
|
142
125
|
requirements:
|
143
|
-
- -
|
126
|
+
- - ">="
|
144
127
|
- !ruby/object:Gem::Version
|
145
128
|
version: '0'
|
146
129
|
- !ruby/object:Gem::Dependency
|
147
130
|
name: databasedotcom
|
148
131
|
requirement: !ruby/object:Gem::Requirement
|
149
|
-
none: false
|
150
132
|
requirements:
|
151
|
-
- -
|
133
|
+
- - ">="
|
152
134
|
- !ruby/object:Gem::Version
|
153
135
|
version: '0'
|
154
136
|
type: :runtime
|
155
137
|
prerelease: false
|
156
138
|
version_requirements: !ruby/object:Gem::Requirement
|
157
|
-
none: false
|
158
139
|
requirements:
|
159
|
-
- -
|
140
|
+
- - ">="
|
160
141
|
- !ruby/object:Gem::Version
|
161
142
|
version: '0'
|
162
143
|
description: ActiveRecord extension & rails engine for syncing data with Salesforce.com
|
@@ -165,50 +146,50 @@ email:
|
|
165
146
|
- nneufeld@infotech.com
|
166
147
|
- acoates@infotech.com
|
167
148
|
- dnoonan@infotech.com
|
168
|
-
- lnediger@infotech.com
|
149
|
+
- lnediger@infotech.com
|
169
150
|
executables: []
|
170
151
|
extensions: []
|
171
152
|
extra_rdoc_files: []
|
172
153
|
files:
|
173
|
-
- README.md
|
174
154
|
- LICENSE
|
155
|
+
- README.md
|
156
|
+
- app/controllers/salesforce_ar_sync/soap_message_controller.rb
|
157
|
+
- config/routes.rb
|
175
158
|
- lib/generators/salesforce_ar_sync/configuration/configuration_generator.rb
|
176
159
|
- lib/generators/salesforce_ar_sync/configuration/templates/salesforce_ar_sync.yml
|
177
160
|
- lib/generators/salesforce_ar_sync/migrations/migrations_generator.rb
|
178
161
|
- lib/generators/salesforce_ar_sync/migrations/templates/migration.rb
|
162
|
+
- lib/salesforce_ar_sync.rb
|
179
163
|
- lib/salesforce_ar_sync/engine.rb
|
180
164
|
- lib/salesforce_ar_sync/extenders/salesforce_syncable.rb
|
181
165
|
- lib/salesforce_ar_sync/ip_constraint.rb
|
166
|
+
- lib/salesforce_ar_sync/railtie.rb
|
182
167
|
- lib/salesforce_ar_sync/salesforce_object_sync.rb
|
183
168
|
- lib/salesforce_ar_sync/salesforce_sync.rb
|
184
169
|
- lib/salesforce_ar_sync/soap_handler/base.rb
|
185
170
|
- lib/salesforce_ar_sync/soap_handler/delete.rb
|
186
171
|
- lib/salesforce_ar_sync/version.rb
|
187
|
-
- lib/salesforce_ar_sync.rb
|
188
|
-
- app/controllers/salesforce_ar_sync/soap_message_controller.rb
|
189
|
-
- config/routes.rb
|
190
172
|
homepage: http://github.com/InfoTech/
|
191
173
|
licenses: []
|
174
|
+
metadata: {}
|
192
175
|
post_install_message:
|
193
176
|
rdoc_options: []
|
194
177
|
require_paths:
|
195
178
|
- lib
|
196
179
|
required_ruby_version: !ruby/object:Gem::Requirement
|
197
|
-
none: false
|
198
180
|
requirements:
|
199
|
-
- -
|
181
|
+
- - ">="
|
200
182
|
- !ruby/object:Gem::Version
|
201
183
|
version: '0'
|
202
184
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
203
|
-
none: false
|
204
185
|
requirements:
|
205
|
-
- -
|
186
|
+
- - ">="
|
206
187
|
- !ruby/object:Gem::Version
|
207
188
|
version: '0'
|
208
189
|
requirements: []
|
209
190
|
rubyforge_project:
|
210
|
-
rubygems_version:
|
191
|
+
rubygems_version: 2.4.7
|
211
192
|
signing_key:
|
212
|
-
specification_version:
|
193
|
+
specification_version: 4
|
213
194
|
summary: ActiveRecord extension & rails engine for syncing data with Salesforce.com
|
214
195
|
test_files: []
|