restforce 1.5.2 → 1.5.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of restforce might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 85b66c52befacd436944640621d9834ba8437936
4
- data.tar.gz: f64960b6e5498618a837d900d1b21ae90621b397
3
+ metadata.gz: cea59c76c61a80f9b37c19dd5fcf0dc65724c706
4
+ data.tar.gz: 803df3bf79c4f7852dd1b1f604ec394981675ac6
5
5
  SHA512:
6
- metadata.gz: 4d28877615344a8a0c36112d564826b8ecdacc20aad84c4e2f4b8195cdd696bd1317eaa838d3eed87fbfc99d0dceb6efab0d4416c8f410dbc918a594bbfe0af8
7
- data.tar.gz: 7fcf33ec632e6314f411e2dd4d406f2d3d1c7b98923a0d81d0387efd2a5e7d65fbb132f9c47d28b057fa334d05501876c5198424312e145d9784421311b24564
6
+ metadata.gz: dc604478ae597a50c0f7ca90236df153a3065f3adca8527012f28e2904e71e0ccda68adedb372e88f183598d99054776cc4e7d5ba5823af200d77bb1fbf3526b
7
+ data.tar.gz: 5b4fb8dff7ea15b51cb6a6e64d7e3d60985eaa46e2fdf7054725c1c3790faaacbdec056757083a47461462a3b0d6362811725dd019e767932d187c70728fc4d1
@@ -1,3 +1,12 @@
1
+ ## 1.5.3 (Jun 26, 2015)
2
+
3
+ * Fixed a bug with `update!` and `upsert!` mutating provided attributes (@timrogers)
4
+ * Added note about thread safety to `README.md` (@epbarger)
5
+ * Improved documentation for `select` in `README.md` (@theSteveMitchell)
6
+ * Tweaked and improved consistency of `README.md` (@timrogers)
7
+ * Pass through blocks given to `Restforce.new` (@jxa)
8
+ * Add `#page_size` to `Restforce::Collection` (@theSteveMitchell)
9
+
1
10
  ## 1.5.2 (Apr 29, 2015)
2
11
 
3
12
  * Better autopagination performance #141 @th7
data/README.md CHANGED
@@ -37,7 +37,7 @@ Or install it yourself as:
37
37
 
38
38
  ## Usage
39
39
 
40
- Restforce is designed with flexibility and ease of use in mind. By default, all api calls will
40
+ Restforce is designed with flexibility and ease of use in mind. By default, all API calls will
41
41
  return [Hashie::Mash](https://github.com/intridea/hashie/tree/v1.2.0) objects,
42
42
  so you can do things like `client.query('select Id, (select Name from Children__r) from Account').Children__r.first.Name`.
43
43
 
@@ -52,6 +52,8 @@ If you're using the gem to interact with a single org (maybe you're building som
52
52
  salesforce integration internally?) then you should use the username/password
53
53
  authentication method.
54
54
 
55
+ It is also important to note that the client object should not be reused across different threads, otherwise you may encounter thread-safety issues.
56
+
55
57
  #### OAuth token authentication
56
58
 
57
59
  ```ruby
@@ -60,7 +62,7 @@ client = Restforce.new :oauth_token => 'oauth token',
60
62
  ```
61
63
 
62
64
  Although the above will work, you'll probably want to take advantage of the
63
- (re)authentication middleware by specifying a refresh token, client id and client secret:
65
+ (re)authentication middleware by specifying a `refresh_token`, `client_id` and `client_secret`:
64
66
 
65
67
  ```ruby
66
68
  client = Restforce.new :oauth_token => 'oauth token',
@@ -82,7 +84,7 @@ client = Restforce.new :username => 'foo',
82
84
  :client_secret => 'client_secret'
83
85
  ```
84
86
 
85
- You can also set the username, password, security token, client id and client
87
+ You can also set the username, password, security token, client ID and client
86
88
  secret in environment variables:
87
89
 
88
90
  ```bash
@@ -96,9 +98,10 @@ export SALESFORCE_CLIENT_SECRET="client secret"
96
98
  ```ruby
97
99
  client = Restforce.new
98
100
  ```
101
+
99
102
  ### Proxy Support
100
103
 
101
- You can specify a http proxy using the :proxy_uri option, as follows:
104
+ You can specify a HTTP proxy using the `proxy_uri` option, as follows, or by setting the `PROXY_URI` environment variable:
102
105
 
103
106
  ```ruby
104
107
  client = Restforce.new :username => 'foo',
@@ -108,7 +111,8 @@ client = Restforce.new :username => 'foo',
108
111
  :client_secret => 'client_secret',
109
112
  :proxy_uri => 'http://proxy.example.com:123'
110
113
  ```
111
- This paramter also will accept 'http://user@password:proxy.example.com:123' or using the environemnt variable PROXY_URI.
114
+
115
+ You may specify a username and password for the proxy with a URL along the lines of 'http://user@password:proxy.example.com:123'.
112
116
 
113
117
  #### Sandbox Orgs
114
118
 
@@ -118,11 +122,11 @@ You can connect to sandbox orgs by specifying a host. The default host is
118
122
  ```ruby
119
123
  client = Restforce.new :host => 'test.salesforce.com'
120
124
  ```
121
- The host can also be set with the environment variable SALESFORCE_HOST.
125
+ The host can also be set with the environment variable `SALESFORCE_HOST`.
122
126
 
123
127
  #### Global configuration
124
128
 
125
- You can set any of the options passed into Restforce.new globally:
129
+ You can set any of the options passed into `Restforce.new` globally:
126
130
 
127
131
  ```ruby
128
132
  Restforce.configure do |config|
@@ -133,8 +137,8 @@ end
133
137
 
134
138
  ### Bang! methods
135
139
 
136
- All the CRUD methods (create, update, upsert, destroy) have equivalent methods with
137
- a ! at the end (create!, update!, upsert!, destroy!), which can be used if you need
140
+ All the CRUD methods (`create`, `update`, `upsert`, `destroy`) have equivalent methods with
141
+ a ! at the end (`create!`, `update!`, `upsert!`, `destroy!`), which can be used if you need
138
142
  to do some custom error handling. The bang methods will raise exceptions, while the
139
143
  non-bang methods will return false in the event that an exception is raised. This
140
144
  works similarly to ActiveRecord.
@@ -176,14 +180,12 @@ client.find('Account', '1234', 'Some_External_Id_Field__c')
176
180
 
177
181
  ### select
178
182
 
179
- ```ruby
180
- client.select('Account', '001D000000INjVe', ["Id"])
181
- # => {"attributes" : {"type" : "Account","url" : "/services/data/v20.0/sobjects/Account/001D000000INjVe"},
182
- # "Id" : "001D000000INjVe"}
183
+ `select` allows the fetching of a specific list of fields from a single object. It requires an `external_id` lookup, but is often much faster than an arbitrary query.
183
184
 
185
+ ```ruby
186
+ # Select the `Id` column from a record with `Some_External_Id_Field__c` set to '001D000000INjVe'
184
187
  client.select('Account', '001D000000INjVe', ["Id"], 'Some_External_Id_Field__c')
185
- # => {"attributes" : {"type" : "Account","url" : "/services/data/v20.0/sobjects/Account/Some_External_Id_Field__c/001D000000INjVe"},
186
- # "Id" : "003F000000BGIn3"}
188
+ # => {"attributes" : {"type" : "Account","url" : "/services/data/v20.0/sobjects/Account/Some_External_Id_Field__c/001D000000INjVe"}, "Id" : "003F000000BGIn3"}
187
189
  ```
188
190
 
189
191
  ### search
@@ -193,7 +195,7 @@ client.select('Account', '001D000000INjVe', ["Id"], 'Some_External_Id_Field__c')
193
195
  client.search('FIND {bar}')
194
196
  # => #<Restforce::Collection >
195
197
 
196
- # Find accounts match the term 'genepoint' and return the Name field
198
+ # Find accounts matching the term 'genepoint' and return the `Name` field
197
199
  client.search('FIND {genepoint} RETURNING Account (Name)').map(&:Name)
198
200
  # => ['GenePoint']
199
201
  ```
@@ -209,7 +211,7 @@ client.create('Account', Name: 'Foobar Inc.')
209
211
  ### update
210
212
 
211
213
  ```ruby
212
- # Update the Account with Id '0016000000MRatd'
214
+ # Update the Account with `Id` '0016000000MRatd'
213
215
  client.update('Account', Id: '0016000000MRatd', Name: 'Whizbang Corp')
214
216
  # => true
215
217
  ```
@@ -217,14 +219,14 @@ client.update('Account', Id: '0016000000MRatd', Name: 'Whizbang Corp')
217
219
  ### upsert
218
220
 
219
221
  ```ruby
220
- # Update the record with external ID of 12
222
+ # Update the record with external `External__c` external ID set to '12'
221
223
  client.upsert('Account', 'External__c', External__c: 12, Name: 'Foobar')
222
224
  ```
223
225
 
224
226
  ### destroy
225
227
 
226
228
  ```ruby
227
- # Delete the Account with Id '0016000000MRatd'
229
+ # Delete the Account with `Id` '0016000000MRatd'
228
230
  client.destroy('Account', '0016000000MRatd')
229
231
  # => true
230
232
  ```
@@ -232,11 +234,11 @@ client.destroy('Account', '0016000000MRatd')
232
234
  ### describe
233
235
 
234
236
  ```ruby
235
- # get the global describe for all sobjects
237
+ # Get the global describe for all sobjects
236
238
  client.describe
237
239
  # => { ... }
238
240
 
239
- # get the describe for the Account object
241
+ # Get the describe for the Account object
240
242
  client.describe('Account')
241
243
  # => { ... }
242
244
  ```
@@ -244,11 +246,11 @@ client.describe('Account')
244
246
  ### describe_layouts
245
247
 
246
248
  ```ruby
247
- # get layouts for an sobject type
249
+ # Get layouts for an sobject type
248
250
  client.describe_layout('Account')
249
251
  # => { ... }
250
252
 
251
- # get the details for a specific layout
253
+ # Get the details for a specific layout by its ID
252
254
  client.describe_layouts('Account', '012E0000000RHEp')
253
255
  # => { ... }
254
256
  ```
@@ -257,12 +259,13 @@ client.describe_layouts('Account', '012E0000000RHEp')
257
259
 
258
260
 
259
261
  ```ruby
262
+ # Fetch picklist value for Account's `Type` field
260
263
  client.picklist_values('Account', 'Type')
261
264
  # => [#<Restforce::Mash label="Prospect" value="Prospect">]
262
265
 
263
266
  # Given a custom object named Automobile__c with picklist fields
264
- # Model__c and Make__c, where Model__c depends on the value of
265
- # Make__c.
267
+ # `Model__c` and `Make__c`, where options for `Model__c` depends on the value of
268
+ # `Make__c`.
266
269
  client.picklist_values('Automobile__c', 'Model__c', :valid_for => 'Honda')
267
270
  # => [#<Restforce::Mash label="Civic" value="Civic">, ... ]
268
271
  ```
@@ -270,7 +273,7 @@ client.picklist_values('Automobile__c', 'Model__c', :valid_for => 'Honda')
270
273
  ### user_info
271
274
 
272
275
  ```ruby
273
- # get info about the logged-in user
276
+ # Get info about the logged-in user
274
277
  client.user_info
275
278
  # => #<Restforce::Mash active=true display_name="Chatty Sassy" email="user@example.com" ... >
276
279
  ```
@@ -44,16 +44,16 @@ module Restforce
44
44
  # Alias for Restforce::Data::Client.new
45
45
  #
46
46
  # Shamelessly pulled from https://github.com/pengwynn/octokit/blob/master/lib/octokit.rb
47
- def new(*args)
48
- data(*args)
47
+ def new(*args, &block)
48
+ data(*args, &block)
49
49
  end
50
50
 
51
- def data(*args)
52
- Restforce::Data::Client.new(*args)
51
+ def data(*args, &block)
52
+ Restforce::Data::Client.new(*args, &block)
53
53
  end
54
54
 
55
- def tooling(*args)
56
- Restforce::Tooling::Client.new(*args)
55
+ def tooling(*args, &block)
56
+ Restforce::Tooling::Client.new(*args, &block)
57
57
  end
58
58
 
59
59
  # Helper for decoding signed requests.
@@ -20,6 +20,10 @@ module Restforce
20
20
  end
21
21
  end
22
22
 
23
+ # Return the size of each page in the collection
24
+ def page_size
25
+ @raw_page['records'].size
26
+ end
23
27
 
24
28
  # Return the size of the Collection without making any additional requests.
25
29
  def size
@@ -220,9 +220,10 @@ module Restforce
220
220
  # Returns true if the sobject was successfully updated.
221
221
  # Raises an exception if an error is returned from Salesforce.
222
222
  def update!(sobject, attrs)
223
- id = attrs.delete(attrs.keys.find { |k| k.to_s.downcase == 'id' })
223
+ id = attrs.fetch(attrs.keys.find { |k, v| k.to_s.downcase == 'id' }, nil)
224
224
  raise ArgumentError, 'Id field missing from attrs.' unless id
225
- api_patch "sobjects/#{sobject}/#{id}", attrs
225
+ attrs_without_id = attrs.reject { |k, v| k.to_s.downcase == "id" }
226
+ api_patch "sobjects/#{sobject}/#{id}", attrs_without_id
226
227
  true
227
228
  end
228
229
 
@@ -261,8 +262,9 @@ module Restforce
261
262
  # Returns the Id of the newly created record if the record was created.
262
263
  # Raises an exception if an error is returned from Salesforce.
263
264
  def upsert!(sobject, field, attrs)
264
- external_id = attrs.delete(attrs.keys.find { |k| k.to_s.downcase == field.to_s.downcase })
265
- response = api_patch "sobjects/#{sobject}/#{field.to_s}/#{external_id}", attrs
265
+ external_id = attrs.fetch(attrs.keys.find { |k, v| k.to_s.downcase == field.to_s.downcase }, nil)
266
+ attrs_without_field = attrs.reject { |k, v| k.to_s.downcase == field.to_s.downcase }
267
+ response = api_patch "sobjects/#{sobject}/#{field.to_s}/#{external_id}", attrs_without_field
266
268
  (response.body && response.body['id']) ? response.body['id'] : true
267
269
  end
268
270
 
@@ -319,13 +321,13 @@ module Restforce
319
321
  # id - The id of the record. If field is specified, id should be the id
320
322
  # of the external field.
321
323
  # select - A String array denoting the fields to select. If nil or empty array
322
- # is passed, all fields are selected.
324
+ # is passed, all fields are selected.
323
325
  # field - External ID field to use (default: nil).
324
326
  #
325
327
  def select(sobject, id, select, field=nil)
326
328
  path = field ? "sobjects/#{sobject}/#{field}/#{id}" : "sobjects/#{sobject}/#{id}"
327
329
  path << "?fields=#{select.join(",")}" if select && select.any?
328
-
330
+
329
331
  api_get(path).body
330
332
  end
331
333
 
@@ -127,6 +127,7 @@ module Restforce
127
127
  # Faraday adapter to use. Defaults to Faraday.default_adapter.
128
128
  option :adapter, :default => lambda { Faraday.default_adapter }
129
129
 
130
+ # TODO: Rename this to `SALESFORCE_PROXY_URI` in next major version
130
131
  option :proxy_uri, :default => lambda { ENV['PROXY_URI'] }
131
132
 
132
133
  # A Proc that is called with the response body after a successful authentication.
@@ -1,3 +1,3 @@
1
1
  module Restforce
2
- VERSION = '1.5.2'
2
+ VERSION = '1.5.3'
3
3
  end
@@ -13,6 +13,7 @@ describe Restforce::Collection do
13
13
  its(:size) { should eq 1 }
14
14
  its(:has_next_page?) { should be_false }
15
15
  it { should have_client client }
16
+ its(:page_size) { should eq 1 }
16
17
 
17
18
  describe 'each record' do
18
19
  it { should be_all { |record| expect(record).to be_a Restforce::SObject } }
@@ -34,6 +35,7 @@ describe Restforce::Collection do
34
35
  its(:first) { should be_a Restforce::SObject }
35
36
  its(:current_page) { should be_a Array }
36
37
  its(:current_page) { should have(1).element }
38
+ its(:page_size) { should eq 1 }
37
39
  end
38
40
 
39
41
  context 'when all of the values are being requested' do
@@ -177,11 +177,11 @@ describe Restforce::Concerns::API do
177
177
  subject(:result) { client.update!(sobject, attrs) }
178
178
 
179
179
  context 'when the id field is present' do
180
- let(:attrs) { { :id => '1234' } }
180
+ let(:attrs) { { :id => '1234', :StageName => "Call Scheduled" } }
181
181
 
182
182
  it 'sends an HTTP PATCH, and returns true' do
183
183
  client.should_receive(:api_patch).
184
- with('sobjects/Whizbang/1234', attrs)
184
+ with('sobjects/Whizbang/1234', { :StageName => "Call Scheduled" })
185
185
  expect(result).to be_true
186
186
  end
187
187
  end
@@ -96,4 +96,14 @@ describe Restforce do
96
96
  end
97
97
  end
98
98
  end
99
+
100
+ describe '.new' do
101
+ it 'calls its block' do
102
+ checker = double(:block_checker)
103
+ expect(checker).to receive(:check!).once
104
+ Restforce.new do |builder|
105
+ checker.check!
106
+ end
107
+ end
108
+ end
99
109
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restforce
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.2
4
+ version: 1.5.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric J. Holmes
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-29 00:00:00.000000000 Z
11
+ date: 2015-06-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -272,7 +272,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
272
272
  version: '0'
273
273
  requirements: []
274
274
  rubyforge_project:
275
- rubygems_version: 2.2.2
275
+ rubygems_version: 2.4.7
276
276
  signing_key:
277
277
  specification_version: 4
278
278
  summary: A lightweight ruby client for the Salesforce REST api.