clearbit 0.2.7 → 0.3.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/CODEOWNERS +3 -0
- data/LICENSE +21 -0
- data/README.md +87 -3
- data/clearbit.gemspec +2 -0
- data/examples/name_domain.rb +4 -0
- data/examples/prospector.rb +5 -4
- data/examples/reveal.rb +11 -0
- data/examples/risk.rb +13 -0
- data/examples/risk_flag.rb +35 -0
- data/lib/clearbit.rb +4 -1
- data/lib/clearbit/analytics.rb +62 -0
- data/lib/clearbit/analytics/LICENSE +10 -0
- data/lib/clearbit/analytics/README.md +114 -0
- data/lib/clearbit/analytics/backoff_policy.rb +49 -0
- data/lib/clearbit/analytics/client.rb +189 -0
- data/lib/clearbit/analytics/defaults.rb +36 -0
- data/lib/clearbit/analytics/field_parser.rb +192 -0
- data/lib/clearbit/analytics/logging.rb +60 -0
- data/lib/clearbit/analytics/message_batch.rb +72 -0
- data/lib/clearbit/analytics/request.rb +134 -0
- data/lib/clearbit/analytics/response.rb +15 -0
- data/lib/clearbit/analytics/utils.rb +91 -0
- data/lib/clearbit/analytics/worker.rb +66 -0
- data/lib/clearbit/audiences.rb +14 -0
- data/lib/clearbit/enrichment.rb +1 -0
- data/lib/clearbit/enrichment/news.rb +18 -0
- data/lib/clearbit/name_domain.rb +17 -0
- data/lib/clearbit/risk.rb +1 -1
- data/lib/clearbit/version.rb +1 -1
- data/lib/clearbit/webhook.rb +3 -1
- data/spec/lib/clearbit/analytics_spec.rb +66 -0
- data/spec/lib/clearbit/prospector_spec.rb +12 -2
- data/spec/support/helpers.rb +3 -1
- metadata +27 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 775ec8d65111d426a0ec0424135c0f070c3d9e6834f818dfb902650f761836f3
|
4
|
+
data.tar.gz: 0c8cd65375787f5df66bc3821ac154bcac21d649b6e97e8804953ae4255463a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 24fe794b5ed903da7d941fffbbdfe0fbd956bb7aabdb7bb2d2d66d412892d01b1ab551de7c28f48d72f66a04a1772d2ba7edfad2eb3c58fd5007874087851a86
|
7
|
+
data.tar.gz: bad29a9ca346fd5accb3441bc1c9bc3272830bb2c15c5c5bc14198c68608100aca97dc7725a7a1d150e8b1066f767404ca575fbc860beae6ec3202edb53e247e
|
data/.github/CODEOWNERS
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 Clearbit.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
CHANGED
@@ -35,9 +35,36 @@ person = result.person
|
|
35
35
|
company = result.company
|
36
36
|
```
|
37
37
|
|
38
|
-
Passing the `stream` option makes the operation blocking - it could hang for 4-5 seconds if we haven't seen the email before. Alternatively you can use our [webhook](https://clearbit.com/docs#webhooks) API.
|
38
|
+
Passing the `stream` option makes the operation blocking - it could hang for 4-5 seconds if we haven't seen the email before. Alternatively you can use our [webhook](https://clearbit.com/docs#webhooks) API.
|
39
|
+
|
40
|
+
Without the `stream` option, the operation is non-blocking, and we will immediately return either the enriched data or `Clearbit::Pending` object.
|
41
|
+
|
42
|
+
```ruby
|
43
|
+
result = Clearbit::Enrichment.find(email: 'alex@alexmaccaw.com')
|
44
|
+
|
45
|
+
if result.pending?
|
46
|
+
# Lookup queued - try again later
|
47
|
+
end
|
48
|
+
|
49
|
+
# Later
|
50
|
+
unless result.pending?
|
51
|
+
person = result.person
|
52
|
+
company = result.company
|
53
|
+
end
|
54
|
+
|
55
|
+
```
|
56
|
+
|
57
|
+
In either case, if a person or company can't be found, the result will be `nil`.
|
39
58
|
|
40
59
|
See the [documentation](https://clearbit.com/docs#person-api) for more information.
|
60
|
+
## Name to Domain
|
61
|
+
|
62
|
+
To find the domain based on the name of a resource, you can use the `NameDomain` API.
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
name = Clearbit::NameDomain.find(name: 'Uber')
|
66
|
+
```
|
67
|
+
For more information look at the [documentation](https://dashboard.clearbit.com/docs?ruby#name-to-domain-api).
|
41
68
|
|
42
69
|
## Company lookup
|
43
70
|
|
@@ -51,6 +78,52 @@ If the company can't be found, then `nil` will be returned.
|
|
51
78
|
|
52
79
|
See the [documentation](https://clearbit.com/docs#company-api) for more information.
|
53
80
|
|
81
|
+
## Analytics
|
82
|
+
|
83
|
+
*NOTE:* We **strongly** recommend using `clearbit.js` for Analytics and integrating with Clearbit X. It handles a lot of complexity, like generating `anonymous_id`s and associating them with `user_id`s when a user is identified. It also automatically tracks `page` views with the full data set.
|
84
|
+
|
85
|
+
### Identifying Users
|
86
|
+
|
87
|
+
Identify users by sending their `user_id`, and adding details like their `email` and `company_domain` to create People and Companies inside of Clearbit X.
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
Clearbit::Analytics.identify(
|
91
|
+
user_id: '1234', # Required if no anonymous_id is sent. The user's ID in your database.
|
92
|
+
anonymous_id: session[:anonymous_id], # Required if no user_id is sent. A UUID to track anonymous users.
|
93
|
+
traits: {
|
94
|
+
email: 'david@clearbitexample.com', # Optional, but strongly recommended
|
95
|
+
company_domain: 'clearbit.com', # Optional, but strongly recommended
|
96
|
+
first_name: 'David', # Optional
|
97
|
+
last_name: 'Lumley', # Optional
|
98
|
+
# … other analytical traits can also be sent, like the plan a user is on etc
|
99
|
+
},
|
100
|
+
context: {
|
101
|
+
ip: '89.102.33.1' # Optional, but strongly recommended when identifying users
|
102
|
+
} # as they sign up, or log in
|
103
|
+
)
|
104
|
+
```
|
105
|
+
|
106
|
+
### Page Views
|
107
|
+
|
108
|
+
Use the `page` method, and send the users `anonymous_id` along with the `url` they're viewing, and the `ip` the request comes from in order to create Companies inside of Clearbit X and track their page views.
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
Clearbit::Analytics.page(
|
112
|
+
user_id: '1234', # Required if no anonymous_id is sent. The user's ID in your database.
|
113
|
+
anonymous_id: session[:anonymous_id], # Required if no user_id is sent. A UUID to track anonymous users.
|
114
|
+
name: 'Clearbit Ruby Library', # Optional, but strongly recommended
|
115
|
+
properties: {
|
116
|
+
url: 'https://github.com/clearbit/clearbit-ruby?utm_source=google', # Required. Likely to be request.referer
|
117
|
+
path: '/clearbit/clearbit-ruby', # Optional, but strongly recommended
|
118
|
+
search: '?utm_source=google', # Optional, but strongly recommended
|
119
|
+
referrer: nil, # Optional. Unlikely to be request.referrer.
|
120
|
+
},
|
121
|
+
context: {
|
122
|
+
ip: '89.102.33.1', # Optional, but strongly recommended.
|
123
|
+
},
|
124
|
+
)
|
125
|
+
```
|
126
|
+
|
54
127
|
## Other APIs
|
55
128
|
|
56
129
|
For more info on our other APIs (such as the Watchlist or Discover APIs), please see our [main documentation](https://clearbit.com/docs).
|
@@ -62,7 +135,7 @@ For rack apps use the `Clearbit::Webhook` module to wrap deserialization and ver
|
|
62
135
|
``` ruby
|
63
136
|
post '/v1/webhooks/clearbit' do
|
64
137
|
begin
|
65
|
-
webhook = Clearbit::Webhook.new(env)
|
138
|
+
webhook = Clearbit::Webhook.new(request.env)
|
66
139
|
webhook.type #=> 'person'
|
67
140
|
webhook.body.name.given_name #=> 'Alex'
|
68
141
|
|
@@ -76,5 +149,16 @@ end
|
|
76
149
|
The global Clearbit.key can be overriden for multi-tenant apps using multiple Clearbit keys like so:
|
77
150
|
|
78
151
|
```ruby
|
79
|
-
webhook = Clearbit::Webhook.new(env, 'CLEARBIT_KEY')
|
152
|
+
webhook = Clearbit::Webhook.new(request.env, 'CLEARBIT_KEY')
|
153
|
+
```
|
154
|
+
|
155
|
+
## Proxy Support
|
156
|
+
|
157
|
+
Passing the proxy option allows you to specify a proxy server to pass the request through.
|
158
|
+
|
159
|
+
``` ruby
|
160
|
+
company = Clearbit::Enrichment::Company.find(
|
161
|
+
domain: 'uber.com',
|
162
|
+
proxy: 'https://user:password@proxyserver.tld:8080'
|
163
|
+
)
|
80
164
|
```
|
data/clearbit.gemspec
CHANGED
@@ -18,6 +18,8 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
+
spec.add_dependency 'json', ['~> 1.7'] if RUBY_VERSION < '1.9'
|
22
|
+
|
21
23
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
22
24
|
spec.add_development_dependency 'net-http-spy'
|
23
25
|
spec.add_development_dependency 'pry'
|
data/examples/prospector.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require 'clearbit'
|
2
|
-
require 'pp'
|
3
2
|
|
4
|
-
|
3
|
+
response = Clearbit::Prospector.search(domain: 'clearbit.com', page: 1)
|
5
4
|
|
6
|
-
|
7
|
-
|
5
|
+
puts "Displaying #{response[:results].size} of #{response[:total]} results:"
|
6
|
+
|
7
|
+
response[:results].each_with_index do |person, index|
|
8
|
+
puts " #{index + 1}. #{person.name.full_name} (#{person.email})"
|
8
9
|
end
|
data/examples/reveal.rb
ADDED
data/examples/risk.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'clearbit'
|
2
|
+
require 'pp'
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
options = {}
|
6
|
+
OptionParser.new do |opts|
|
7
|
+
opts.banner = "Usage: risk_flag.rb [options]"
|
8
|
+
|
9
|
+
opts.on("-iIP", "--ip=IP", "IP address") do |ip|
|
10
|
+
options[:ip] = ip
|
11
|
+
end
|
12
|
+
|
13
|
+
opts.on("-eEMAIL", "--email=EMAIL", "Email address") do |email|
|
14
|
+
options[:email] = email
|
15
|
+
end
|
16
|
+
|
17
|
+
opts.on("-tTYPE", "--type=TYPE", "Type") do |type|
|
18
|
+
options[:type] = type
|
19
|
+
end
|
20
|
+
|
21
|
+
opts.on("-h", "--help", "Prints this help") do
|
22
|
+
puts opts
|
23
|
+
exit
|
24
|
+
end
|
25
|
+
end.parse!
|
26
|
+
|
27
|
+
options[:type] ||= 'spam'
|
28
|
+
|
29
|
+
begin
|
30
|
+
Clearbit::Risk.flag(options)
|
31
|
+
rescue Nestful::Error => err
|
32
|
+
pp err.decoded
|
33
|
+
else
|
34
|
+
puts 'Successfully flagged!'
|
35
|
+
end
|
data/lib/clearbit.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'nestful'
|
2
2
|
require 'clearbit/version'
|
3
|
+
require 'clearbit/analytics'
|
3
4
|
|
4
5
|
module Clearbit
|
5
6
|
def self.api_key=(value)
|
@@ -18,12 +19,14 @@ module Clearbit
|
|
18
19
|
key || raise('Clearbit.key not set')
|
19
20
|
end
|
20
21
|
|
22
|
+
autoload :Audiences, 'clearbit/audiences'
|
21
23
|
autoload :Autocomplete, 'clearbit/autocomplete'
|
22
24
|
autoload :Base, 'clearbit/base'
|
23
|
-
autoload :Enrichment, 'clearbit/enrichment'
|
24
25
|
autoload :Discovery, 'clearbit/discovery'
|
26
|
+
autoload :Enrichment, 'clearbit/enrichment'
|
25
27
|
autoload :Logo, 'clearbit/logo'
|
26
28
|
autoload :Mash, 'clearbit/mash'
|
29
|
+
autoload :NameDomain, 'clearbit/name_domain'
|
27
30
|
autoload :Pending, 'clearbit/pending'
|
28
31
|
autoload :Prospector, 'clearbit/prospector'
|
29
32
|
autoload :Resource, 'clearbit/resource'
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'clearbit/analytics/defaults'
|
2
|
+
require 'clearbit/analytics/utils'
|
3
|
+
require 'clearbit/analytics/field_parser'
|
4
|
+
require 'clearbit/analytics/client'
|
5
|
+
require 'clearbit/analytics/worker'
|
6
|
+
require 'clearbit/analytics/request'
|
7
|
+
require 'clearbit/analytics/response'
|
8
|
+
require 'clearbit/analytics/logging'
|
9
|
+
|
10
|
+
module Clearbit
|
11
|
+
class Analytics
|
12
|
+
# Proxy identify through to a client instance, in order to keep the client
|
13
|
+
# consistent with how the other Clearbit APIs are accessed
|
14
|
+
def self.identify(args)
|
15
|
+
analytics = new(write_key: Clearbit.key)
|
16
|
+
analytics.identify(args)
|
17
|
+
analytics.flush
|
18
|
+
end
|
19
|
+
|
20
|
+
# Proxy page through to a client instance, in order to keep the client
|
21
|
+
# consistent with how the other Clearbit APIs are accessed
|
22
|
+
def self.page(args)
|
23
|
+
analytics = new(write_key: Clearbit.key)
|
24
|
+
analytics.page(args)
|
25
|
+
analytics.flush
|
26
|
+
end
|
27
|
+
|
28
|
+
# Proxy group through to a client instance, in order to keep the client
|
29
|
+
# consistent with how the other Clearbit APIs are accessed
|
30
|
+
def self.group(args)
|
31
|
+
analytics = new(write_key: Clearbit.key)
|
32
|
+
analytics.group(args)
|
33
|
+
analytics.flush
|
34
|
+
end
|
35
|
+
|
36
|
+
# Initializes a new instance of {Clearbit::Analytics::Client}, to which all
|
37
|
+
# method calls are proxied.
|
38
|
+
#
|
39
|
+
# @param options includes options that are passed down to
|
40
|
+
# {Clearbit::Analytics::Client#initialize}
|
41
|
+
# @option options [Boolean] :stub (false) If true, requests don't hit the
|
42
|
+
# server and are stubbed to be successful.
|
43
|
+
def initialize(options = {})
|
44
|
+
Request.stub = options[:stub] if options.has_key?(:stub)
|
45
|
+
@client = Clearbit::Analytics::Client.new options
|
46
|
+
end
|
47
|
+
|
48
|
+
def method_missing(message, *args, &block)
|
49
|
+
if @client.respond_to? message
|
50
|
+
@client.send message, *args, &block
|
51
|
+
else
|
52
|
+
super
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def respond_to_missing?(method_name, include_private = false)
|
57
|
+
@client.respond_to?(method_name) || super
|
58
|
+
end
|
59
|
+
|
60
|
+
include Logging
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2013 Segment Inc. <friends@segment.com>
|
4
|
+
Copyright (c) 2019 Clearbit. <support@clearbit.com>
|
5
|
+
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
7
|
+
|
8
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
9
|
+
|
10
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,114 @@
|
|
1
|
+
# Getting Started with Clearbit::Analytics
|
2
|
+
|
3
|
+
## Initialization
|
4
|
+
|
5
|
+
Make sure you set your `Clearbit.key` as part of your apps initialization, or before you make use of `Clearbit::Analytics`. You can find your secret key at [https://dashboard.clearbit.com/api](https://dashboard.clearbit.com/api)
|
6
|
+
|
7
|
+
`Clearbit.key = 'sk_…'`.
|
8
|
+
|
9
|
+
We also recommend ensuring that every person has a randomly generated `anonymous_id` to aid tracking page events and assist in matching up anonymous traffic to signed in users.
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
class ApplicationController
|
13
|
+
before_action :set_anonymous_id
|
14
|
+
…
|
15
|
+
|
16
|
+
def set_anonymous_id
|
17
|
+
session[:anonymous_id] ||= SecureRandom.uuid
|
18
|
+
end
|
19
|
+
|
20
|
+
…
|
21
|
+
end
|
22
|
+
```
|
23
|
+
|
24
|
+
## Importing Users into X
|
25
|
+
|
26
|
+
You'll want to loop through your users, and call `.identify` for each one, passing the users `id`, and their `email` along with any other traits you value.
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
User.find_in_batches do |users|
|
30
|
+
users.each do |user|
|
31
|
+
Clearbit::Analytics.identify(
|
32
|
+
user_id: user.id, # Required.
|
33
|
+
traits: {
|
34
|
+
email: user.email, # Required.
|
35
|
+
company_domain: user.domain || user.email.split('@').last, # Optional, strongly recommended.
|
36
|
+
first_name: user.first_name, # Optional.
|
37
|
+
last_name: user.last_name, # Optional.
|
38
|
+
# … other analytical traits can also be sent, like the plan a user is on etc.
|
39
|
+
},
|
40
|
+
)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
## Identifying Users on sign up / log in
|
46
|
+
|
47
|
+
Identifying users on sign up, or on log in will help Clearbit X associate the user with anonymous page views.
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
class SessionsController
|
51
|
+
…
|
52
|
+
|
53
|
+
def create
|
54
|
+
…
|
55
|
+
|
56
|
+
identify(current_user)
|
57
|
+
|
58
|
+
…
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def identify(user)
|
64
|
+
Clearbit::Analytics.identify(
|
65
|
+
user_id: user.id, # Required
|
66
|
+
anonymous_id: session[:anonymous_id], # Optional, strongly recommended. Helps Clearbit X associate with anonymous visits.
|
67
|
+
traits: {
|
68
|
+
email: user.email, # Required.
|
69
|
+
company_domain: user.domain || user.email.split('@').last, # Optional, strongly recommended.
|
70
|
+
first_name: user.first_name, # Optional.
|
71
|
+
last_name: user.last_name, # Optional.
|
72
|
+
# … other analytical traits can also be sent, like the plan a user is on etc.
|
73
|
+
},
|
74
|
+
context: {
|
75
|
+
ip: request.ip, # Optional, but strongly recommended. Helps Clearbit X associate with anonymous visits.
|
76
|
+
},
|
77
|
+
)
|
78
|
+
end
|
79
|
+
|
80
|
+
…
|
81
|
+
end
|
82
|
+
```
|
83
|
+
|
84
|
+
## Sending Page views
|
85
|
+
|
86
|
+
Tracking page views is best done using a `anonymous_id` you generate for each user. You'll need to sent the `url` as part of the `properties` hash, and the `ip` as part of the `context` hash. Any other data you can provide will greatly help with segmentation inside of Clearbit X.
|
87
|
+
|
88
|
+
|
89
|
+
```ruby
|
90
|
+
uri = URI(request.referer) # You'll likely want to do some error handling here.
|
91
|
+
|
92
|
+
Clearbit::Analytics.page(
|
93
|
+
user_id: current_user&.id, # Optional
|
94
|
+
anonymous_id: session[:anonymous_id], # Required
|
95
|
+
properties: {
|
96
|
+
url: request.referrer, # Required. Because this is a backend integration, the referrer is the URL that was visited.
|
97
|
+
path: format_path(uri.path), # Optional, but strongly recommended.
|
98
|
+
search: format_search(uri.params), # Optional, but strongly recommended.
|
99
|
+
referrer: nil, # Optional. Not the `request.referer`, but the referrer of the original page view.
|
100
|
+
},
|
101
|
+
context: {
|
102
|
+
ip: request.ip, # Required. Helps Clearbit X associate anonymous visits with Companies.
|
103
|
+
},
|
104
|
+
)
|
105
|
+
|
106
|
+
def format_path(path)
|
107
|
+
path.presence || '/'
|
108
|
+
end
|
109
|
+
|
110
|
+
def format_search(search)
|
111
|
+
return unless search
|
112
|
+
'?' + search
|
113
|
+
end
|
114
|
+
```
|