openstax_active_force 1.0.0
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 +7 -0
- data/.gitignore +17 -0
- data/.mailmap +3 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/CHANGELOG.md +98 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +174 -0
- data/Rakefile +6 -0
- data/active_force.gemspec +30 -0
- data/lib/active_attr/dirty.rb +33 -0
- data/lib/active_force/active_query.rb +155 -0
- data/lib/active_force/association/association.rb +50 -0
- data/lib/active_force/association/belongs_to_association.rb +26 -0
- data/lib/active_force/association/eager_load_projection_builder.rb +60 -0
- data/lib/active_force/association/has_many_association.rb +33 -0
- data/lib/active_force/association/relation_model_builder.rb +70 -0
- data/lib/active_force/association.rb +28 -0
- data/lib/active_force/attribute.rb +30 -0
- data/lib/active_force/mapping.rb +78 -0
- data/lib/active_force/query.rb +110 -0
- data/lib/active_force/sobject.rb +210 -0
- data/lib/active_force/standard_types.rb +357 -0
- data/lib/active_force/table.rb +37 -0
- data/lib/active_force/version.rb +3 -0
- data/lib/active_force.rb +13 -0
- data/lib/generators/active_force/model/USAGE +8 -0
- data/lib/generators/active_force/model/model_generator.rb +62 -0
- data/lib/generators/active_force/model/templates/model.rb.erb +5 -0
- data/spec/active_force/active_query_spec.rb +178 -0
- data/spec/active_force/association/relation_model_builder_spec.rb +62 -0
- data/spec/active_force/association_spec.rb +157 -0
- data/spec/active_force/attribute_spec.rb +27 -0
- data/spec/active_force/callbacks_spec.rb +20 -0
- data/spec/active_force/mapping_spec.rb +18 -0
- data/spec/active_force/query_spec.rb +126 -0
- data/spec/active_force/sobject/includes_spec.rb +290 -0
- data/spec/active_force/sobject/table_name_spec.rb +27 -0
- data/spec/active_force/sobject_spec.rb +398 -0
- data/spec/active_force/table_spec.rb +25 -0
- data/spec/active_force_spec.rb +7 -0
- data/spec/fixtures/sobject/single_sobject_hash.yml +26 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/support/fixture_helpers.rb +45 -0
- data/spec/support/restforce_factories.rb +9 -0
- data/spec/support/sobjects.rb +97 -0
- data/spec/support/whizbang.rb +30 -0
- metadata +196 -0
@@ -0,0 +1,398 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveForce::SObject do
|
4
|
+
let(:sobject_hash) { YAML.load(fixture('sobject/single_sobject_hash')) }
|
5
|
+
let(:client) { double 'Client' }
|
6
|
+
|
7
|
+
before do
|
8
|
+
ActiveForce.sfdc_client = client
|
9
|
+
end
|
10
|
+
|
11
|
+
describe ".new" do
|
12
|
+
it 'should assigns values when are passed by parameters' do
|
13
|
+
expect(Whizbang.new({ text: 'some text' }).text).to eq 'some text'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe ".build" do
|
18
|
+
let(:sobject){ Whizbang.build sobject_hash }
|
19
|
+
|
20
|
+
it "build a valid sobject from a JSON" do
|
21
|
+
expect(sobject).to be_an_instance_of Whizbang
|
22
|
+
end
|
23
|
+
|
24
|
+
it "sets the values' types from the sf_type" do
|
25
|
+
expect(sobject.boolean).to be_an_instance_of TrueClass
|
26
|
+
expect(sobject.checkbox).to be_an_instance_of FalseClass
|
27
|
+
expect(sobject.date).to be_an_instance_of Date
|
28
|
+
expect(sobject.datetime).to be_an_instance_of DateTime
|
29
|
+
expect(sobject.percent).to be_an_instance_of Float
|
30
|
+
expect(sobject.text).to be_an_instance_of String
|
31
|
+
expect(sobject.picklist_multiselect).to be_an_instance_of String
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe ".field" do
|
36
|
+
it "add a mappings" do
|
37
|
+
expect(Whizbang.mappings).to include(
|
38
|
+
checkbox: 'Checkbox_Label',
|
39
|
+
text: 'Text_Label',
|
40
|
+
date: 'Date_Label',
|
41
|
+
datetime: 'DateTime_Label',
|
42
|
+
picklist_multiselect: 'Picklist_Multiselect_Label'
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "set an attribute" do
|
47
|
+
%w[checkbox text date datetime picklist_multiselect].each do |name|
|
48
|
+
expect(Whizbang.attribute_names).to include(name)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it "uses Salesforce API naming conventions by default" do
|
53
|
+
expect(Whizbang.mappings[:estimated_close_date]).to eq 'Estimated_Close_Date__c'
|
54
|
+
end
|
55
|
+
|
56
|
+
describe 'having an id' do
|
57
|
+
it 'has one by default' do
|
58
|
+
expect(Territory.new).to respond_to(:id)
|
59
|
+
expect(Territory.mappings[:id]).to eq 'Id'
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'can be overridden' do
|
63
|
+
expect(Quota.new).to respond_to(:id)
|
64
|
+
expect(Quota.mappings[:id]).to eq 'Bar_Id__c'
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
context 'as: :multi_picklist' do
|
69
|
+
before do
|
70
|
+
class IceCream < ActiveForce::SObject
|
71
|
+
field :flavors, as: :multi_picklist
|
72
|
+
end
|
73
|
+
sundae.clear_changes_information
|
74
|
+
sundae.flavors = %w(chocolate vanilla strawberry)
|
75
|
+
end
|
76
|
+
|
77
|
+
context 'on create' do
|
78
|
+
let(:sundae) { IceCream.new }
|
79
|
+
it 'formats the picklist values' do
|
80
|
+
expect(client).to receive(:create!).with('IceCream__c', {'Flavors__c' => 'chocolate;vanilla;strawberry'})
|
81
|
+
sundae.save
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'on update' do
|
86
|
+
let(:sundae) { IceCream.new(id: '1') }
|
87
|
+
it 'formats the picklist values' do
|
88
|
+
expect(client).to receive(:update!).with('IceCream__c', {'Flavors__c' => 'chocolate;vanilla;strawberry', 'Id' => '1'})
|
89
|
+
sundae.save
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
describe "CRUD" do
|
97
|
+
let(:instance){ Whizbang.new(id: '1') }
|
98
|
+
|
99
|
+
describe '#update' do
|
100
|
+
|
101
|
+
context 'with valid attributes' do
|
102
|
+
before do
|
103
|
+
expected_args = [
|
104
|
+
Whizbang.table_name,
|
105
|
+
{'Text_Label' => 'some text', 'Boolean_Label' => false, 'Id' => '1', "Updated_From__c"=>"Rails"}
|
106
|
+
]
|
107
|
+
expect(client).to receive(:update!).with(*expected_args).and_return('id')
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'delegates to the Client with create! and sets the id' do
|
111
|
+
expect(instance.update( text: 'some text', boolean: false )).to eq(true)
|
112
|
+
expect(instance.text).to eq('some text')
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'with invalid attributes' do
|
117
|
+
it 'sets the error on the instance' do
|
118
|
+
expect(instance.update( boolean: true )).to eq(false)
|
119
|
+
expect(instance.errors).to be_present
|
120
|
+
expect(instance.errors.full_messages.count).to eq(1)
|
121
|
+
expect(instance.errors.full_messages[0]).to eq("Percent can't be blank")
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
describe ".update!" do
|
127
|
+
context 'with valid attributes' do
|
128
|
+
describe 'and without a ClientError' do
|
129
|
+
before do
|
130
|
+
expected_args = [
|
131
|
+
Whizbang.table_name,
|
132
|
+
{'Text_Label' => 'some text', 'Boolean_Label' => false, 'Id' => '1', "Updated_From__c"=>"Rails"}
|
133
|
+
]
|
134
|
+
expect(client).to receive(:update!).with(*expected_args).and_return('id')
|
135
|
+
end
|
136
|
+
it 'saves successfully' do
|
137
|
+
expect(instance.update!( text: 'some text', boolean: false )).to eq(true)
|
138
|
+
expect(instance.text).to eq('some text')
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe 'and with a ClientError' do
|
143
|
+
let(:faraday_error){ Faraday::Error::ClientError.new('Some String') }
|
144
|
+
|
145
|
+
before{ expect(client).to receive(:update!).and_raise(faraday_error) }
|
146
|
+
|
147
|
+
it 'raises an error' do
|
148
|
+
expect{ instance.update!( text: 'some text', boolean: false ) }.to raise_error(Faraday::Error::ClientError)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
context 'with invalid attributes' do
|
154
|
+
let(:instance){ Whizbang.new boolean: true }
|
155
|
+
|
156
|
+
it 'raises an error' do
|
157
|
+
expect{ instance.update!( text: 'some text', boolean: true ) }.to raise_error(ActiveForce::RecordInvalid)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
describe '#create' do
|
163
|
+
context 'with valid attributes' do
|
164
|
+
before do
|
165
|
+
expect(client).to receive(:create!).and_return('id')
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'delegates to the Client with create! and sets the id' do
|
169
|
+
expect(instance.create).to be_instance_of(Whizbang)
|
170
|
+
expect(instance.id).to eq('id')
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
context 'with invalid attributes' do
|
176
|
+
let(:instance){ Whizbang.new boolean: true }
|
177
|
+
|
178
|
+
it 'sets the error on the instance' do
|
179
|
+
expect(instance.create).to be_instance_of(Whizbang)
|
180
|
+
expect(instance.id).to eq(nil)
|
181
|
+
expect(instance.errors).to be_present
|
182
|
+
expect(instance.errors.full_messages.count).to eq(1)
|
183
|
+
expect(instance.errors.full_messages[0]).to eq("Percent can't be blank")
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
describe '#create!' do
|
189
|
+
context 'with valid attributes' do
|
190
|
+
describe 'and without a ClientError' do
|
191
|
+
|
192
|
+
before{ expect(client).to receive(:create!).and_return('id') }
|
193
|
+
|
194
|
+
it 'saves successfully' do
|
195
|
+
expect(instance.create!).to be_instance_of(Whizbang)
|
196
|
+
expect(instance.id).to eq('id')
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe 'and with a ClientError' do
|
201
|
+
let(:faraday_error){ Faraday::Error::ClientError.new('Some String') }
|
202
|
+
|
203
|
+
before{ expect(client).to receive(:create!).and_raise(faraday_error) }
|
204
|
+
|
205
|
+
it 'raises an error' do
|
206
|
+
expect{ instance.create! }.to raise_error(Faraday::Error::ClientError)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
context 'with invalid attributes' do
|
212
|
+
let(:instance){ Whizbang.new boolean: true }
|
213
|
+
|
214
|
+
it 'raises an error' do
|
215
|
+
expect{ instance.create! }.to raise_error(ActiveForce::RecordInvalid)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
describe "#destroy" do
|
221
|
+
it "should send client :destroy! with its id" do
|
222
|
+
expect(client).to receive(:destroy!).with 'Whizbang__c', '1'
|
223
|
+
instance.destroy
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
describe 'self.create' do
|
228
|
+
before do
|
229
|
+
expect(client).to receive(:create!).with(Whizbang.table_name, 'Text_Label' => 'some text', 'Updated_From__c'=>'Rails').and_return('id')
|
230
|
+
end
|
231
|
+
|
232
|
+
it 'should create a new instance' do
|
233
|
+
expect(Whizbang.create(text: 'some text')).to be_instance_of(Whizbang)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
describe "#count" do
|
239
|
+
let(:count_response){ [Restforce::Mash.new(expr0: 1)] }
|
240
|
+
|
241
|
+
it "responds to count" do
|
242
|
+
expect(Whizbang).to respond_to(:count)
|
243
|
+
end
|
244
|
+
|
245
|
+
it "sends the query to the client" do
|
246
|
+
expect(client).to receive(:query).and_return(count_response)
|
247
|
+
expect(Whizbang.count).to eq(1)
|
248
|
+
end
|
249
|
+
|
250
|
+
end
|
251
|
+
|
252
|
+
describe "#find_by" do
|
253
|
+
it "should query the client, with the SFDC field names and correctly enclosed values" do
|
254
|
+
expect(client).to receive(:query).with("SELECT #{Whizbang.fields.join ', '} FROM Whizbang__c WHERE (Id = 123) AND (Text_Label = 'foo') LIMIT 1")
|
255
|
+
Whizbang.find_by id: 123, text: "foo"
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
describe '#reload' do
|
260
|
+
let(:client) do
|
261
|
+
double("sfdc_client", query: [Restforce::Mash.new(Id: 1, Name: 'Jeff')])
|
262
|
+
end
|
263
|
+
let(:quota){ Quota.new(id: '1') }
|
264
|
+
let(:territory){ Territory.new(id: '1', quota_id: '1') }
|
265
|
+
|
266
|
+
before do
|
267
|
+
ActiveForce.sfdc_client = client
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'clears cached associations' do
|
271
|
+
soql = "SELECT Id, Bar_Id__c FROM Quota__c WHERE (Id = '1') LIMIT 1"
|
272
|
+
expect(client).to receive(:query).twice.with soql
|
273
|
+
allow(Territory).to receive(:find){ territory }
|
274
|
+
territory.quota
|
275
|
+
territory.quota
|
276
|
+
territory.reload
|
277
|
+
territory.quota
|
278
|
+
end
|
279
|
+
|
280
|
+
it "refreshes the object's attributes" do
|
281
|
+
territory.name = 'Walter'
|
282
|
+
expect(territory.name).to eq 'Walter'
|
283
|
+
territory.reload
|
284
|
+
expect(territory.name).to eq 'Jeff'
|
285
|
+
expect(territory.changed_attributes).to be_empty
|
286
|
+
end
|
287
|
+
|
288
|
+
it 'returns the same object' do
|
289
|
+
allow(Territory).to receive(:find){ Territory.new }
|
290
|
+
expected = territory
|
291
|
+
expect(territory.reload).to eql expected
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
describe '#persisted?' do
|
296
|
+
context 'with an id' do
|
297
|
+
let(:instance){ Territory.new(id: '00QV0000004jeqNMAT') }
|
298
|
+
|
299
|
+
it 'returns true' do
|
300
|
+
expect(instance).to be_persisted
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
context 'without an id' do
|
305
|
+
let(:instance){ Territory.new }
|
306
|
+
|
307
|
+
it 'returns false' do
|
308
|
+
expect(instance).to_not be_persisted
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
describe 'logger output' do
|
314
|
+
let(:instance){ Whizbang.new }
|
315
|
+
|
316
|
+
before do
|
317
|
+
allow(instance).to receive(:create!).and_raise(Faraday::Error::ClientError.new(double))
|
318
|
+
end
|
319
|
+
|
320
|
+
it 'catches and logs the error' do
|
321
|
+
expect(instance).to receive(:logger_output).and_return(false)
|
322
|
+
instance.save
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
describe ".save!" do
|
327
|
+
let(:instance){ Whizbang.new }
|
328
|
+
|
329
|
+
context 'with valid attributes' do
|
330
|
+
describe 'and without a ClientError' do
|
331
|
+
before{ expect(client).to receive(:create!).and_return('id') }
|
332
|
+
it 'saves successfully' do
|
333
|
+
expect(instance.save!).to eq(true)
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
describe 'and with a ClientError' do
|
338
|
+
let(:faraday_error){ Faraday::Error::ClientError.new('Some String') }
|
339
|
+
|
340
|
+
before{ expect(client).to receive(:create!).and_raise(faraday_error) }
|
341
|
+
|
342
|
+
it 'raises an error' do
|
343
|
+
expect{ instance.save! }.to raise_error(Faraday::Error::ClientError)
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
context 'with invalid attributes' do
|
349
|
+
let(:instance){ Whizbang.new boolean: true }
|
350
|
+
|
351
|
+
it 'raises an error' do
|
352
|
+
expect{ instance.save! }.to raise_error(ActiveForce::RecordInvalid)
|
353
|
+
end
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
describe ".save" do
|
358
|
+
let(:instance){ Whizbang.new }
|
359
|
+
|
360
|
+
context 'with valid attributes' do
|
361
|
+
describe 'and without a ClientError' do
|
362
|
+
before{ expect(client).to receive(:create!).and_return('id') }
|
363
|
+
it 'saves successfully' do
|
364
|
+
expect(instance.save).to eq(true)
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
describe 'and with a ClientError' do
|
369
|
+
let(:faraday_error){ Faraday::Error::ClientError.new('Some String') }
|
370
|
+
before{ expect(client).to receive(:create!).and_raise(faraday_error) }
|
371
|
+
it 'returns false' do
|
372
|
+
expect(instance.save).to eq(false)
|
373
|
+
end
|
374
|
+
it 'sets the error on the instance' do
|
375
|
+
instance.save
|
376
|
+
expect(instance.errors).to be_present
|
377
|
+
expect(instance.errors.full_messages.count).to eq(1)
|
378
|
+
expect(instance.errors.full_messages[0]).to eq('Some String')
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
context 'with invalid attributes' do
|
384
|
+
let(:instance){ Whizbang.new boolean: true }
|
385
|
+
|
386
|
+
it 'does not save' do
|
387
|
+
expect(instance.save).to eq(false)
|
388
|
+
end
|
389
|
+
|
390
|
+
it 'sets the error on the instance' do
|
391
|
+
instance.save
|
392
|
+
expect(instance.errors).to be_present
|
393
|
+
expect(instance.errors.full_messages.count).to eq(1)
|
394
|
+
expect(instance.errors.full_messages[0]).to eq("Percent can't be blank")
|
395
|
+
end
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveForce::Table do
|
4
|
+
describe '#table_name' do
|
5
|
+
let(:table) { ActiveForce::Table }
|
6
|
+
|
7
|
+
it 'Use the class name adding "__c"' do
|
8
|
+
expect(table.new('Custom').name).to eq('Custom__c')
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'with standard SObject types it does not add the "__c"' do
|
12
|
+
expect(table.new('Account').name).to eq('Account')
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'with a namespace' do
|
16
|
+
it "the namespace is not included" do
|
17
|
+
expect(table.new('Foo::Bar').name).to eq('Bar__c')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'standard types are inferred correctly' do
|
21
|
+
expect(table.new('Foo::Account').name).to eq('Account')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
attributes:
|
2
|
+
type: 'Whizbang'
|
3
|
+
url: '/services/data/v20.0/sobjects/Whizbang/foo'
|
4
|
+
Checkbox_Label: false
|
5
|
+
Text_Label: 'Hi there!'
|
6
|
+
Date_Label: '2010-01-01'
|
7
|
+
DateTime_Label: '2011-07-07T00:37:00.000+0000'
|
8
|
+
Picklist_Multiselect_Label: 'four;six'
|
9
|
+
Percent_Label: 20
|
10
|
+
Boolean_Label: true
|
11
|
+
|
12
|
+
ParentWhizbang__r:
|
13
|
+
Name: 'Parent Whizbang'
|
14
|
+
Text_Label: 'Hello'
|
15
|
+
attributes:
|
16
|
+
type: 'Whizbang'
|
17
|
+
url: '/services/data/v20.0/sobjects/Whizbang/bar'
|
18
|
+
|
19
|
+
Whizbangs__r:
|
20
|
+
totalSize: 1
|
21
|
+
done: true
|
22
|
+
records:
|
23
|
+
- attributes:
|
24
|
+
type: 'Whizbang__c'
|
25
|
+
url: '/services/data/v24.0/sobjects/Whizbang__c/a00E0000004D5lsIAC'
|
26
|
+
Name: 'Child Whizbang'
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
2
|
+
require 'active_force'
|
3
|
+
Dir["./spec/support/**/*"].sort.each { |f| require f }
|
4
|
+
require 'pry'
|
5
|
+
|
6
|
+
ActiveSupport::Inflector.inflections do |inflect|
|
7
|
+
inflect.plural 'quota', 'quotas'
|
8
|
+
inflect.plural 'Quota', 'Quotas'
|
9
|
+
inflect.singular 'quota', 'quota'
|
10
|
+
inflect.singular 'Quota', 'Quota'
|
11
|
+
end
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
config.order = :random
|
15
|
+
config.include RestforceFactories
|
16
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module FixtureHelpers
|
2
|
+
module InstanceMethods
|
3
|
+
|
4
|
+
def stub_api_request(endpoint, options={})
|
5
|
+
options = {
|
6
|
+
:method => :get,
|
7
|
+
:status => 200,
|
8
|
+
:api_version => Restforce.configuration.api_version
|
9
|
+
}.merge(options)
|
10
|
+
|
11
|
+
stub = stub_request(options[:method], %r{/services/data/v#{options[:api_version]}/#{endpoint}})
|
12
|
+
stub = stub.with(:body => options[:with_body]) if options[:with_body] && !RUBY_VERSION.match(/^1.8/)
|
13
|
+
stub = stub.to_return(:status => options[:status], :body => fixture(options[:fixture]), :headers => { 'Content-Type' => 'application/json'}) if options[:fixture]
|
14
|
+
stub
|
15
|
+
end
|
16
|
+
|
17
|
+
def stub_login_request(options={})
|
18
|
+
stub = stub_request(:post, "https://login.salesforce.com/services/oauth2/token")
|
19
|
+
stub = stub.with(:body => options[:with_body]) if options[:with_body] && !RUBY_VERSION.match(/^1.8/)
|
20
|
+
stub
|
21
|
+
end
|
22
|
+
|
23
|
+
def fixture(f)
|
24
|
+
File.read(File.expand_path("../../fixtures/#{f}.yml", __FILE__))
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
module ClassMethods
|
30
|
+
def requests(endpoint, options={})
|
31
|
+
before do
|
32
|
+
(@requests ||= []) << stub_api_request(endpoint, options)
|
33
|
+
end
|
34
|
+
|
35
|
+
after do
|
36
|
+
@requests.each { |request| expect(request).to have_been_requested }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
RSpec.configure do |config|
|
43
|
+
config.include FixtureHelpers::InstanceMethods
|
44
|
+
config.extend FixtureHelpers::ClassMethods
|
45
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
|
2
|
+
class Comment < ActiveForce::SObject
|
3
|
+
self.table_name = "Comment__c"
|
4
|
+
field :post_id, from: "PostId"
|
5
|
+
field :poster_id, from: 'PosterId__c'
|
6
|
+
field :fancy_post_id, from: 'FancyPostId'
|
7
|
+
field :body
|
8
|
+
belongs_to :post
|
9
|
+
end
|
10
|
+
class Post < ActiveForce::SObject
|
11
|
+
self.table_name = "Post__c"
|
12
|
+
field :title
|
13
|
+
has_many :comments
|
14
|
+
has_many :impossible_comments, model: Comment, scoped_as: ->{ where('1 = 0') }
|
15
|
+
has_many :reply_comments, model: Comment, scoped_as: ->(post){ where(body: "RE: #{post.title}").order('CreationDate DESC') }
|
16
|
+
has_many :ugly_comments, { model: Comment }
|
17
|
+
has_many :poster_comments, { foreign_key: :poster_id, model: Comment }
|
18
|
+
end
|
19
|
+
class Territory < ActiveForce::SObject
|
20
|
+
field :quota_id, from: "Quota__c"
|
21
|
+
field :name, from: 'Name'
|
22
|
+
belongs_to :quota
|
23
|
+
end
|
24
|
+
class PrezClub < ActiveForce::SObject
|
25
|
+
field :quota_id, from: 'QuotaId'
|
26
|
+
belongs_to :quota
|
27
|
+
end
|
28
|
+
class Quota < ActiveForce::SObject
|
29
|
+
field :id, from: 'Bar_Id__c'
|
30
|
+
has_many :prez_clubs
|
31
|
+
has_many :territories
|
32
|
+
end
|
33
|
+
class Opportunity < ActiveForce::SObject
|
34
|
+
field :account_id, from: 'AccountId'
|
35
|
+
belongs_to :account
|
36
|
+
end
|
37
|
+
class Account < ActiveForce::SObject
|
38
|
+
field :owner_id, from: 'OwnerId'
|
39
|
+
has_many :opportunities
|
40
|
+
belongs_to :owner
|
41
|
+
end
|
42
|
+
class Owner < ActiveForce::SObject
|
43
|
+
has_many :accounts
|
44
|
+
end
|
45
|
+
class Custom < ActiveForce::SObject; end
|
46
|
+
class EnforcedTableName < ActiveForce::SObject
|
47
|
+
self.table_name = 'Forced__c'
|
48
|
+
end
|
49
|
+
|
50
|
+
module Foo
|
51
|
+
class Bar < ActiveForce::SObject; end
|
52
|
+
class Opportunity < ActiveForce::SObject
|
53
|
+
field :account_id, from: 'AccountId'
|
54
|
+
field :partner_account_id, from: 'Partner_Account_Id__c'
|
55
|
+
end
|
56
|
+
class Account < ActiveForce::SObject
|
57
|
+
has_many :opportunities, model: Foo::Opportunity
|
58
|
+
has_many :partner_opportunities, foreign_key: :partner_account_id, model: Foo::Opportunity
|
59
|
+
end
|
60
|
+
class Lead < ActiveForce::SObject; end
|
61
|
+
class Attachment < ActiveForce::SObject
|
62
|
+
field :lead_id, from: 'Lead_Id__c'
|
63
|
+
field :fancy_lead_id, from: 'LeadId'
|
64
|
+
belongs_to :lead, model: Foo::Lead
|
65
|
+
belongs_to :fancy_lead, model: Foo::Lead, foreign_key: :fancy_lead_id
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
module Salesforce
|
70
|
+
class PrezClub < ActiveForce::SObject
|
71
|
+
field :quota_id, from: 'QuotaId'
|
72
|
+
end
|
73
|
+
class Quota < ActiveForce::SObject
|
74
|
+
has_many :prez_clubs, model: PrezClub
|
75
|
+
end
|
76
|
+
class Widget < ActiveForce::SObject
|
77
|
+
self.table_name = 'Tegdiw__c'
|
78
|
+
end
|
79
|
+
class Territory < ActiveForce::SObject
|
80
|
+
field :quota_id, from: "QuotaId"
|
81
|
+
field :widget_id, from: 'WidgetId'
|
82
|
+
belongs_to :quota, model: Salesforce::Quota, foreign_key: :quota_id
|
83
|
+
belongs_to :widget, model: Salesforce::Widget, foreign_key: :widget_id
|
84
|
+
end
|
85
|
+
class User < ActiveForce::SObject
|
86
|
+
end
|
87
|
+
class Opportunity < ActiveForce::SObject
|
88
|
+
field :owner_id, from: 'OwnerId'
|
89
|
+
field :account_id, from: 'AccountId'
|
90
|
+
field :business_partner
|
91
|
+
belongs_to :owner, model: Salesforce::User, foreign_key: :owner_id, relationship_name: 'Owner'
|
92
|
+
end
|
93
|
+
class Account < ActiveForce::SObject
|
94
|
+
field :business_partner
|
95
|
+
has_many :partner_opportunities, model: Opportunity, scoped_as: ->(account){ where(business_partner: account.business_partner).includes(:owner) }
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
class Whizbang < ActiveForce::SObject
|
2
|
+
|
3
|
+
field :id, from: 'Id'
|
4
|
+
field :checkbox, from: 'Checkbox_Label', as: :boolean
|
5
|
+
field :text, from: 'Text_Label'
|
6
|
+
field :date, from: 'Date_Label', as: :date
|
7
|
+
field :datetime, from: 'DateTime_Label', as: :datetime
|
8
|
+
field :picklist_multiselect, from: 'Picklist_Multiselect_Label', as: :multipicklist
|
9
|
+
field :boolean, from: 'Boolean_Label', as: :boolean
|
10
|
+
field :percent, from: 'Percent_Label', as: :percent
|
11
|
+
field :estimated_close_date, as: :datetime
|
12
|
+
field :updated_from, as: :datetime
|
13
|
+
field :dirty_attribute, as: :boolean
|
14
|
+
|
15
|
+
before_save :set_as_updated_from_rails
|
16
|
+
after_save :mark_dirty
|
17
|
+
|
18
|
+
validates :percent, presence: true, if: :boolean
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def set_as_updated_from_rails
|
23
|
+
self.updated_from = 'Rails'
|
24
|
+
end
|
25
|
+
|
26
|
+
def mark_dirty
|
27
|
+
self.dirty_attribute = true
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|