ruby_hubspot_api 0.1.2.1 → 0.2.1.pre.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
- SHA256:
3
- metadata.gz: b77e20469ffc97b7330e7a163ee5ed4d43b1bef4a17ee7a1eb38663157d3faab
4
- data.tar.gz: 52088790ea4ccea816e0b2efc0846331dcffbc29fd0d01c80e16baa9dbafb331
2
+ SHA1:
3
+ metadata.gz: 2ca83fa3cba8c574d585b31a359da74678d405d2
4
+ data.tar.gz: 151f119e552b17faff4d921cda1ceec62a3fc045
5
5
  SHA512:
6
- metadata.gz: eab5e7e4ab612428b97b31b81c06c25562f6dd0ef89eba5f47628bb1dbc79dd84fa893c868f6515f0f2d2b435016e8ed50c897e7aa97ac66355b136c1778aea3
7
- data.tar.gz: '08dbe5b3847885d286e7f26142e8d2925583195d1c624158d165e023cc2fc3b7cb4482eab4db459c3ecf50aae226457a3487e3fbe8242eb8c59c346c1e0132bb'
6
+ metadata.gz: e2e95c0a9ef1b69ff862c7843bbb100b23d57fe29cfea0d2042a7593dc3760307d48027fc0b54a6ae05bd39c4721db7603e04a7b16a5ec51b50a1becc436fdc1
7
+ data.tar.gz: 9dd953ca1946b3f9c3f1d0616f377a330f7e894f6a0f1a1aa6e98fde137015b6c39148dec58437c5cf027d89b9e096dbeb36b144a368ed8f1e61aa2a673305d7
@@ -0,0 +1,47 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Ruby
9
+
10
+ on:
11
+ push:
12
+ branches: [ "main" ]
13
+ pull_request:
14
+ branches: [ "main" ]
15
+
16
+ permissions:
17
+ contents: read
18
+
19
+ jobs:
20
+ test:
21
+
22
+ runs-on: ubuntu-latest
23
+ strategy:
24
+ matrix:
25
+ ruby-version: ['2.5', '2.6', '2.7', '3.0']
26
+
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+
30
+ - name: Set up Ruby
31
+ uses: ruby/setup-ruby@v1
32
+ with:
33
+ ruby-version: ${{ matrix.ruby-version }}
34
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
35
+
36
+ - name: Run tests
37
+ run: HUBSPOT_LOG_LEVEL=FATAL bundle exec rspec
38
+
39
+ - name: Upload coverage to Codecov
40
+ run: bash <(curl -s https://codecov.io/bash)
41
+ env:
42
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
43
+
44
+ - name: Upload coverage to Codacy
45
+ run: bash <(curl -Ls https://coverage.codacy.com/get.sh)
46
+ env:
47
+ CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
data/.gitignore CHANGED
@@ -6,3 +6,4 @@
6
6
  # rspec failure tracking
7
7
  .rspec_status
8
8
  .pry_history
9
+ .ruby-version
data/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
+ ## v.0.2.0
1
2
 
2
- ## v0.1.1
3
+ - Get the development dependencies right!
4
+ - Bump the version again
5
+ - describe find_by method
6
+ - update lock
7
+ - batch :sparkle: upsert spec
8
+ - Borrowing Object#blank? method cos it actually really helps...
9
+ - batch implemntation
10
+ - logger.debug the post body and response body
11
+ - Adds a changes? Method on resource
12
+ - Adds instance method resource_name on resource
13
+ - Ensure keys are stringified
14
+ - Add all end points to the batch spec
15
+ - Adds create and archive methods to batches
16
+ - Tidy up resource code
17
+ - Cover the previously nocov'd code
18
+ - Add api client logging spec
19
+ - add configurable timeouts to requests
20
+ - Move rate limit handling to the client
21
+ - Simplify mocked responses in batch spec
22
+ - Adds PagedBatch as pager for batch/read request
23
+ - Update the Readme to add Batch operations
24
+ - #5 batch_updating
25
+
26
+ ## v0.1.2
3
27
 
4
28
  - initial setup
5
29
  - Setup the configuration block
@@ -46,6 +70,17 @@
46
70
  - adds the version numbers to the gemspec
47
71
  - Fix dependencies
48
72
  - bump version
73
+ - Fix the Readme
74
+ - Sure the search param is values where passing an array
75
+ - update changelog and Gemfile.lock
76
+ - bump version
77
+
78
+ ## v0.1.1
79
+
80
+ - Fix the Readme
81
+ - Sure the search param is values where passing an array
82
+ - update changelog and Gemfile.lock
83
+ - bump version
49
84
 
50
85
  ## v0.1.0
51
86
 
data/Gemfile.lock CHANGED
@@ -1,30 +1,24 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ruby_hubspot_api (0.1.1)
5
- bundler (>= 2.0)
6
- dotenv (>= 2.0)
4
+ ruby_hubspot_api (0.2.1)
7
5
  httparty (>= 0.1, < 1.0)
8
- pry (>= 0.1)
9
- pry-byebug (>= 3.0)
10
- rspec (>= 3.0)
11
- simplecov (>= 0.22, < 1.0)
12
- vcr (>= 6.0)
13
- webmock (>= 3.0)
14
6
 
15
7
  GEM
16
8
  remote: https://rubygems.org/
17
9
  specs:
18
10
  addressable (2.8.7)
19
11
  public_suffix (>= 2.0.2, < 7.0)
20
- bigdecimal (3.1.8)
12
+ bigdecimal (3.0.2)
21
13
  byebug (11.1.3)
14
+ codecov (0.6.0)
15
+ simplecov (>= 0.15, < 0.22)
22
16
  coderay (1.1.3)
23
17
  crack (1.0.0)
24
18
  bigdecimal
25
19
  rexml
26
20
  diff-lcs (1.5.1)
27
- docile (1.4.1)
21
+ docile (1.3.5)
28
22
  dotenv (2.8.1)
29
23
  hashdiff (1.1.1)
30
24
  httparty (0.21.0)
@@ -33,15 +27,15 @@ GEM
33
27
  method_source (1.1.0)
34
28
  mini_mime (1.1.2)
35
29
  multi_xml (0.6.0)
36
- pry (0.13.1)
30
+ pry (0.14.2)
37
31
  coderay (~> 1.1)
38
32
  method_source (~> 1.0)
39
- pry-byebug (3.9.0)
33
+ pry-byebug (3.8.0)
40
34
  byebug (~> 11.0)
41
- pry (~> 0.13.0)
35
+ pry (~> 0.10)
42
36
  public_suffix (4.0.7)
43
37
  rake (13.2.1)
44
- rexml (3.3.7)
38
+ rexml (3.2.5)
45
39
  rspec (3.13.0)
46
40
  rspec-core (~> 3.13.0)
47
41
  rspec-expectations (~> 3.13.0)
@@ -55,24 +49,35 @@ GEM
55
49
  diff-lcs (>= 1.2.0, < 2.0)
56
50
  rspec-support (~> 3.13.0)
57
51
  rspec-support (3.13.1)
58
- simplecov (0.22.0)
52
+ simplecov (0.18.5)
59
53
  docile (~> 1.1)
60
54
  simplecov-html (~> 0.11)
61
- simplecov_json_formatter (~> 0.1)
62
55
  simplecov-html (0.13.1)
63
- simplecov_json_formatter (0.1.4)
56
+ simplecov-lcov (0.8.0)
64
57
  vcr (6.0.0)
65
- webmock (3.23.1)
58
+ webmock (3.18.1)
66
59
  addressable (>= 2.8.0)
67
60
  crack (>= 0.3.2)
68
61
  hashdiff (>= 0.4.0, < 2.0.0)
69
62
 
70
63
  PLATFORMS
64
+ ruby
71
65
  x86_64-darwin-18
66
+ x86_64-linux
72
67
 
73
68
  DEPENDENCIES
69
+ bundler (>= 2.0, < 2.4.0)
70
+ codecov
71
+ dotenv (>= 2.0)
72
+ pry (>= 0.1)
73
+ pry-byebug (>= 3.0)
74
74
  rake (>= 11.0, < 14.0)
75
+ rspec (>= 3.0)
75
76
  ruby_hubspot_api!
77
+ simplecov
78
+ simplecov-lcov
79
+ vcr (>= 6.0)
80
+ webmock (>= 3.0)
76
81
 
77
82
  BUNDLED WITH
78
- 2.3.26
83
+ 2.2.34
data/README.md CHANGED
@@ -1,8 +1,10 @@
1
1
  # Ruby HubSpot API Gem
2
2
 
3
+ [![codecov](https://codecov.io/gh/sensadrome/ruby_hubspot_api/branch/main/graph/badge.svg)](https://codecov.io/gh/sensadrome/ruby_hubspot_api) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/504ca01245ee4928b6ed0b13801259e7)](https://app.codacy.com/gh/sensadrome/ruby_hubspot_api/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
4
+
3
5
  This gem was largely inspired by [hubspot-api-ruby](https://github.com/captaincontrat/hubspot-api-ruby) which, in turn, was inspired by the [hubspot-ruby](https://github.com/HubspotCommunity/hubspot-ruby) community gem. I wanted to use version 3 of the api and simplify some parts of the interface
4
6
 
5
- The Ruby HubSpot API gem is a starting point for building an ORM-like interface to HubSpot's API.
7
+ The Ruby HubSpot API gem is a starting point for building an ORM-like interface to HubSpot's API.
6
8
 
7
9
  ## Installation
8
10
 
@@ -30,23 +32,58 @@ To authenticate API requests, you need a HubSpot access token. First you will ne
30
32
 
31
33
  You can configure the gem by adding this code to your initializer (for Rails) or to your startup configuration (in any other environment):
32
34
 
35
+ ##### Minimum configuration
36
+
37
+ ```ruby
38
+ Hubspot.configure do |config|
39
+ config.access_token = 'your_access_token'
40
+ end
41
+ ```
42
+
43
+ ##### Full possible configuration
44
+
33
45
  ```ruby
34
46
  Hubspot.configure do |config|
35
47
  config.access_token = 'your_access_token'
48
+ config.portal_id = 'your_portal_id'
49
+ config.client_secret = 'your_client_secret'
50
+ config.logger = Rails.logger
51
+ config.log_level = 'info' # debug,info,warn,error,fatal
52
+ config.timeout = 10 # seconds to timeout all api requests
53
+ config.open_timeout = 5 # open_timeout seconds
54
+ config.read_timeout = 5 # read_timeout seconds
55
+ config.write_timeout = 5 # swrite_timeout econds (ruby >= 2.6)
36
56
  end
37
57
  ```
38
58
 
39
59
  This configuration ensures that your API requests are authenticated using your HubSpot access token.
40
60
 
41
- ## Working with Objects
61
+ ## Working with Resources
42
62
 
43
- This gem allows you to interact with HubSpot objects such as contacts and companies. You can perform operations on individual instances (e.g., creating or updating records) as well as on collections (e.g., listing or searching).
63
+ This gem allows you to interact with Hubspot resources such as contacts and companies. You can perform operations on individual resources (e.g., creating or updating records) as well as on collections (e.g., listing or searching).
44
64
 
45
- ### Instance Methods
65
+ __please note__
46
66
 
47
- #### Creating and Saving an Object
67
+ > In the Hubspot API contacts, companies etc are referred to as "Objects" (e.g. CRM > Objects > Contacts) so when we use the word "Object" (with a capital O) we will be referring to an object in Hubspot
48
68
 
49
- You can instantiate a new resource (such as a contact) by passing a hash of properties when creating the object. After setting the properties, calling `save` will persist the object to the HubSpot API.
69
+ > In this gem we use the term Resource so as not to accidentally overload Object! When we use the term "Resource" we should be referring to the ruby ORM base class and when we say "resource" we should be referring to an instance of this class (or a class that inherits it)
70
+
71
+ ### Hubspot::Resource class
72
+
73
+ This is the base ORM class for all Hubspot CRM objects. You should not operate on this class but with the following classes each of which inherits from Hubspot::Resource
74
+
75
+ ```ruby
76
+ Hubspot::Contact # crm > contacts
77
+ Hubspot::Company # crm > companies
78
+ Hubspot::User # hubspot users (also referred to as 'owners')
79
+ Hubspot::Owner # alias of Hubspot::User if you prefer to use it
80
+ ```
81
+
82
+ however you can [add custom objects of your own](#user-content-custom-resources) based on your own custom defined Objects in Hubspot
83
+
84
+ ### Creating and Saving an Object
85
+
86
+ Create and instance of the resource passing a hash of properties. Calling `save` on the instance will persist the object to the HubSpot API, as well as set the id property (which you can then store in your own database for example)
50
87
 
51
88
  Example:
52
89
 
@@ -60,44 +97,96 @@ new_contact.save
60
97
  puts "New contact ID: #{new_contact.id}"
61
98
  ```
62
99
 
63
- #### Updating an Existing Object
100
+ ### Retreiving an Object
101
+
102
+ If you know the id of the object you can fetch it from the api using the find method
103
+
104
+ ```ruby
105
+ contact = Hubspot::Contact.find(1)
106
+ puts "Contact: #{contact.firstname} #{contact.lastname}"
107
+ ```
108
+
109
+ You can also retrieve a single object by using the `find_by` method. Simply specify the property and the value you want to search on:
110
+
111
+ ```ruby
112
+ # find by email
113
+ contact = Hubspot::Contact.find_by('email', 'john.doe@example.org')
114
+ puts "Contact: #{contact.firstname} #{contact.lastname}"
115
+
116
+ #find by internal id (custom field)
117
+ contact = Hubspot::Contact.find_by('member_id', 123)
118
+ puts "Contact: #{contact.firstname} #{contact.lastname}"
119
+ ```
64
120
 
65
- To update an existing object, you can either modify the object and call `save`, or use the `update` method specifying the properties you want to update
121
+ ### Updating an Existing Object
122
+
123
+ To update an existing object, you can either modify the object and call `save`, or use the `update` method specifying the properties you want to update. You can test whether or not the object will need to upload changes to the api by using the changes? method
66
124
 
67
125
  Example using `save`:
68
126
 
69
127
  ```ruby
70
128
  contact = Hubspot::Contact.find(1)
129
+ contact.changes? # false
130
+
71
131
  contact.lastname = 'DoeUpdated'
132
+ contact.changes? # true
133
+
134
+ # save the updates to Hubspot
72
135
  contact.save # true
136
+ contact.changes? # false
73
137
  ```
74
138
 
75
139
  Example using `update`:
76
140
 
77
141
  ```ruby
78
142
  contact = Hubspot::Contact.find(1)
143
+ # save the updates to Hubspot
79
144
  contact.update(lastname: 'DoeUpdated') # true
80
145
  ```
81
146
 
82
- ### Class Methods
147
+ If you are able to construct an Object with data stored locally you can save the inital `find` api call, but you will need to construct the persisted object specifying the id and a properties hash (as if it came from the api!)
148
+
149
+ Example:
150
+
151
+ ```ruby
152
+ local_contact = Contact.find(contact_id)
153
+
154
+ hubspot_properties = {
155
+ firstname: local_contact.first_name,
156
+ lastname: local_contact.last_name,
157
+ email: local_contact.email,
158
+ # ... more properties...
159
+ }
83
160
 
84
- #### Listing Objects
161
+ hubspot_contact = Hubspot::Contact.new(id: contact.hs_object_id, properties: hubspot_properties )
162
+ hubspot_contact.changes? # false
85
163
 
86
- You can list all objects (such as contacts) using the `list` method, which returns a `PagedCollection`. This collection handles paginated results and responds to methods like `each_page`, `each`, and `all`. You can also pass the `page_size` parameter to control the number of records returned per page.
164
+ # update a custom field "last_contacted"
165
+ # (in the hubspot_contact instance this will be stored in the changes property)
166
+ hubspot_contact.last_contacted = Time.now.utc.iso8601
167
+ hubspot_contact.changes? # true
168
+
169
+ # persist the change to hubspot
170
+ hubspot_contact.save #true
171
+ ```
172
+
173
+ ### Listing Objects
174
+
175
+ You can list all objects (such as contacts) using the `list` method, which returns a `PagedCollection`. This collection handles paginated results and is Enumerable, so responds to methods like `each_page`, `each`, and `all`. You can also pass the `page_size` parameter to control the number of records returned per page.
87
176
 
88
177
  Example:
89
178
 
90
179
  ```ruby
91
180
  contacts = Hubspot::Contact.list(page_size: 10)
92
181
 
93
- # Using each_page to iterate over pages
182
+ # Using each_page to iterate over pages, there will be up to 10 contacts per page
94
183
  contacts.each_page do |page|
95
184
  page.each do |contact|
96
185
  puts "Contact: #{contact.firstname} #{contact.lastname}"
97
186
  end
98
187
  end
99
188
 
100
- # Or iterate over all contacts without worrying about pagination
189
+ # Or iterate over all contacts and the pagination will be handled transparently (page_size still applies)
101
190
  contacts.each do |contact|
102
191
  puts "Contact: #{contact.firstname} #{contact.lastname}"
103
192
  end
@@ -106,23 +195,42 @@ end
106
195
  all_contacts = contacts.all
107
196
  ```
108
197
 
109
- #### Retrieving the first n items
198
+ #### Retrieving the first n items:
110
199
 
111
- You can use the `first` method to retrieve the first item or a specified number of items:
200
+ As mentioned the list method returns a PagedCollection. You can call `first` on the result to retrieve the first item or a specified number of items:
112
201
 
113
202
  ```ruby
114
- contacts = Hubspot::Contact.list(page_size: 10)
203
+ contacts_collection = Hubspot::Contact.list
115
204
 
116
205
  # Retrieve the first contact
117
- first_contact = contacts.first
206
+ first_contact = contacts_collection.first
118
207
 
119
208
  # Retrieve the first 5 contacts
120
- first_five_contacts = contacts.first(5)
209
+ first_five_contacts = contacts_collection.first(5)
121
210
  ```
122
211
 
123
212
  This will automatically set the limits and handle paging for the most efficient API calls while honouring the maximum page count for hubspot resources
124
213
 
125
- #### Searching
214
+ #### Specifying properties
215
+
216
+ By default Hubspot will only send back the [default hubspot properties](https://knowledge.hubspot.com/properties/hubspots-default-contact-properties)
217
+
218
+ You can pass an array of properties to be returned as follows:
219
+
220
+ Example:
221
+
222
+ ```ruby
223
+ # Get the full list of contacts and only return specific properties
224
+ contacts = Hubspot::Contact.list(
225
+ properties: ['firstname', 'lastname', 'email', 'mobile', 'custom_property_1']
226
+ )
227
+
228
+ contacts.each do |contact|
229
+ puts "Name: #{contact.firstname} #{contact.lastname}, Email: #{contact.email}, Mobile: #{contact.mobile} CustomerRef: #{contact.custom_property_1}"
230
+ end
231
+ ```
232
+
233
+ ### Searching
126
234
 
127
235
  You can search for objects by passing query parameters to the `search` method. HubSpot supports several operators such as `eq`, `gte`, `lt`, and `IN` for filtering.
128
236
 
@@ -132,15 +240,21 @@ Example:
132
240
  # Search for contacts with email containing "hubspot.com"
133
241
  contacts = Hubspot::Contact.search(query: { email_contains: 'hubspot.com' })
134
242
 
243
+ puts "Searching for Hubspot staff in the contacts CRM"
244
+ puts ""
245
+
135
246
  contacts.each do |contact|
136
- puts "Found: #{contact.email}"
247
+ puts " Found: #{contact.firstname} #{contact.lastname} (#{contact.email})"
137
248
  end
138
249
 
139
250
  # Search for companies with number of employees greater than or equal to 100
140
251
  companies = Hubspot::Company.search(query: { number_of_employees_gte: 100 })
141
252
 
253
+ puts "Searching for medium to large companies"
254
+ puts ""
255
+
142
256
  companies.each do |company|
143
- puts "Found: #{company.name}, Employees: #{company.number_of_employees}"
257
+ puts " Found: #{company.name} (#{company.number_of_employees} employees)"
144
258
  end
145
259
 
146
260
  # Search for contacts with email in a specific list (IN operator)
@@ -152,15 +266,18 @@ end
152
266
  ```
153
267
 
154
268
  ### Available Search Operators:
155
- - **eq**: Equal to.
269
+ - **contains**: contains <string>
156
270
  - **neq**: Not equal to.
271
+ - **gt**: Greater than.
157
272
  - **gte**: Greater than or equal to.
273
+ - **lt**: Less than.
158
274
  - **lte**: Less than or equal to.
159
275
  - **IN**: Matches any of the values in an array.
160
276
 
161
277
  #### Specifying Properties in Search
162
278
 
163
- When performing a search, you can also specify which properties to return. If you specify any properties, you will only get those properties back, and the default HubSpot properties will not be included automatically.
279
+ When performing a search, you can also specify which properties to return.
280
+ *NB* If you specify any properties, you will only get those properties back, and the default HubSpot properties will not be included automatically.
164
281
 
165
282
  Example:
166
283
 
@@ -172,10 +289,185 @@ contacts = Hubspot::Contact.search(
172
289
  )
173
290
 
174
291
  contacts.each do |contact|
175
- puts "Name: #{contact.firstname} #{contact.lastname}, Email: #{contact.email}, Mobile: #{contact.mobile}"
292
+ puts "Name: #{contact.firstname} #{contact.lastname}, Email: #{contact.email}, Mobile: #{contact.mobile} CustomerRef: #{contact.custom_property_1}"
293
+ end
294
+ ```
295
+
296
+ ## Working with batches
297
+
298
+ ### Hubspot::Batch
299
+
300
+ The `Hubspot::Batch` class allows you to perform batch operations on HubSpot resources, such as contacts or companies. This includes batch `create`, `read`, `update`, `upsert`, and `archive` operations. Below are examples of how to use these methods.
301
+
302
+ #### Batch Create
303
+
304
+ To create new resources in bulk, you can use the `create` method.
305
+
306
+ In this example, `batch.create` triggers the creation of new contacts. After creation, the batch response will include the new IDs assigned to each object by HubSpot which will be assigned to the resources in the batch
307
+
308
+ ```ruby
309
+ contacts = [
310
+ Hubspot::Contact.new(email: 'new.john@example.com', firstname: 'John', lastname: 'Doe'),
311
+ Hubspot::Contact.new(email: 'new.jane@example.com', firstname: 'Jane', lastname: 'Doe')
312
+ ]
313
+
314
+ batch = Hubspot::Batch.new(contacts)
315
+ batch.create
316
+
317
+ batch.resources.each do |contact|
318
+ hubspot_id = contact.id
319
+ # store hubspot_id against a contact....
176
320
  end
177
321
  ```
178
322
 
323
+
324
+ #### Batch Read
325
+
326
+ To read a batch of Objects by their internal hubspot id or by another uniq property you can use the `read` method. You will need to pass the class of the resource, an array of ids and optionally an id_property.
327
+
328
+ For simplicity you can also use the `batch_read` method of the corresponding class (e.g. Hubspot::Contacts, Hubspot::Company etc) passing an array of ids and optionally an id_property (defaults to 'id'). This method will return a Hubspot::Batch and the results will be in "resources"
329
+
330
+ Example using `read` along with the Hubspot id of several companies...
331
+
332
+ ```ruby
333
+ # Grab an array of hubspot company ids to read from the api...
334
+ company_ids = my_companies.collect(&:hubspot_id).compact
335
+
336
+ # this will grab all the results from the api handling paging automagically
337
+ batch = Hubspot::Batch.read(Hubspot::Company, company_ids)
338
+ companies = batch.resources
339
+
340
+ # Or using the domain field
341
+ # Grab an array of company domains
342
+ company_domains = my_companies.collect(&:domain_name).compact
343
+
344
+ # calls /crm/v3/objects/companies/batch/read
345
+ batch = Hubspot::Batch.read(Hubspot::Company, company_domains, id_property: 'domain')
346
+ companies = batch.resources
347
+ ```
348
+
349
+ Example of reading contacts by email and the helper method `batch_read`
350
+ By using this method you can page through the results as needed or collect them
351
+
352
+ ```ruby
353
+ email_addresses = my_selected_contacts.collect(&:email).compact
354
+
355
+ batch = Hubspot::Contact.batch_read(email_addresses, id_property: 'email')
356
+
357
+ batch.each_page do |contacts|
358
+ contacts.each do |contact|
359
+ # persist some data locally
360
+ update_local_contact_from_hubspot(contact)
361
+ end
362
+ # stop the api calls if a condition is met
363
+ # break if <condition>
364
+ end
365
+ ```
366
+
367
+ Finally there is another helper method `batch_read_all` on any Hubspot::Resource class (Hubspot::Contact, Hubspot::Company, Hubspot::User etc) which will read all of the resources and return a HubSpot::Batch (with all of the resources).
368
+
369
+ You can then update the resources and call `update` on the batch.... see below
370
+
371
+ #### Batch Update
372
+
373
+ For updating existing resources in bulk, you can use the `update` method. If you want to locally create an object without calling the API you specify the id and pass any properties in the 'properties' hash (this is how the objects are returned from Hubspot)
374
+
375
+ ```ruby
376
+ contacts = [
377
+ Hubspot::Contact.new(id: 1, properties: { firstname: 'John', lastname: 'Doe' }),
378
+ Hubspot::Contact.new(id: 2, properties: { firstname: 'Jane', lastname: 'Doe' })
379
+ ]
380
+
381
+ # make a changes to each contact
382
+ contacts.each { |contact| contact.last_contacted = Time.now.utc.iso8601 }
383
+
384
+ batch = Hubspot::Batch.new(contacts)
385
+ batch.update
386
+ ```
387
+
388
+ Example using a batch
389
+ ```ruby
390
+ user_ids = my_selected_users.collect(&:hubspot_id).compact
391
+ batch = Hubspot::User.batch_read(user_ids)
392
+
393
+ batch.resources.each do |hubspot_user|
394
+ # some logic or method to set any new/changed properties on hubspot_user
395
+ hubspot_user.sales_total = fetch_sales_total(user.email)
396
+ end
397
+
398
+ # now we have a batch with changed resources we can update the batch
399
+ batch.update # true
400
+ ```
401
+
402
+ #### Batch Upsert
403
+
404
+ The `upsert` method allows you to insert new records or update existing ones. You’ll need to specify an `id_property` (like `email`) to uniquely identify records
405
+
406
+ ```ruby
407
+ contacts = [
408
+ Hubspot::Contact.new(email: 'new.john@example.com', firstname: 'John', lastname: 'Doe'),
409
+ Hubspot::Contact.new(email: 'new.jane@example.com', firstname: 'Jane', lastname: 'Doe')
410
+ ]
411
+
412
+ batch = Hubspot::Batch.new(contacts, id_property: 'email')
413
+ batch.upsert
414
+ ```
415
+
416
+ In this example, if a contact with the given email already exists in HubSpot, it will be updated. If it doesn't, a new contact will be created.
417
+
418
+ #### Batch Archive
419
+
420
+ To archive objects in bulk, you can use the `archive` method. This removes the objects from HubSpot.
421
+
422
+ ```ruby
423
+ contacts = Hubspot::Contact.search(query: { email_contains: 'hubspot.com' }).all
424
+
425
+ batch = Hubspot::Batch.new(contacts)
426
+ batch.archive
427
+ ```
428
+
429
+ The `archive` method sends a batch request to HubSpot to archive the objects. If any of the objects fail to be archived, you can check for partial success using the `partial_success?` method.
430
+
431
+ #### Error Handling and Success Checks
432
+
433
+ You can check whether the batch operation was entirely successful, partially successful, or if any failures occurred:
434
+
435
+ ```ruby
436
+ if batch.all_successful?
437
+ puts "All resources were successfully processed."
438
+ elsif batch.partial_success?
439
+ puts "Some resources were successfully processed, but others failed."
440
+ else
441
+ puts "The batch operation failed."
442
+ end
443
+ ```
444
+
445
+ ## Custom Resources
446
+
447
+ If you have defined custom objects you can easily add them by creating a class that inherits from `Hubspot::Resource`
448
+
449
+ ```ruby
450
+ # lib/hubspot/projects.rb
451
+
452
+ require 'ruby_hubspot_api' # if not required by bundler already...
453
+
454
+ module Hubspot
455
+ class Project < Resource
456
+
457
+ # resource_name (part of the url in the api) will default
458
+ # to a simple plural of the class name - in this case 'projects'
459
+ # if the url for your custom object is different you can override it
460
+
461
+ def resource_name
462
+ 'company_projects'
463
+ end
464
+ end
465
+ end
466
+
467
+ projects = Hubspot::Projects.search(query: { status_in: ['upcoming', 'active', 'overrun'] }).all
468
+
469
+ ```
470
+
179
471
  ## Contributing
180
472
 
181
473
  There is much to do (including writing a TODO list, or at least adding issues in github!) but this should provide a solid start