rack-tracker 1.7.0 → 1.8.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 +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +22 -0
- data/lib/rack/tracker.rb +1 -0
- data/lib/rack/tracker/google_global/google_global.rb +32 -0
- data/lib/rack/tracker/google_global/template/google_global.erb +19 -0
- data/lib/rack/tracker/handler.rb +2 -1
- data/lib/rack/tracker/version.rb +1 -1
- data/spec/handler/google_global_spec.rb +187 -0
- data/spec/integration/google_global_integration_spec.rb +30 -0
- data/spec/support/metal_controller.rb +4 -0
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e9d098ca10113dc7340ab5e268dec40e8b0143a0d1284d1caaeac155510c1bd6
|
4
|
+
data.tar.gz: c84e057fd1021e504ff749fd5a70e3a79ced5343d39720af987fb5b3783a38b3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a140e3e30f813d916adec3e6a6aed6919b53d72281d2880ae81ecc035d980c9c330fce2b0bd85497bb92e20172db0aa5bffa8edd0e9fd538f15380be66124aa
|
7
|
+
data.tar.gz: 357e0828908134f96ed5370554b17d9ecdce43a098493471dc9a5807e1af7f186ce05bb7a5674ac2f36a0f6eddefdf93742be93f8682573266065bd368c087d6
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -20,6 +20,7 @@ to the middleware stack the second part are the service-handlers that you're goi
|
|
20
20
|
in your application. It's easy to add your own [custom handlers](#custom-handlers),
|
21
21
|
but to get you started we're shipping support for the following services out of the box:
|
22
22
|
|
23
|
+
* [Google Global Site Tag](#google-global)
|
23
24
|
* [Google Analytics](#google-analytics)
|
24
25
|
* [Google Adwords Conversion](#google-adwords-conversion)
|
25
26
|
* [Google Tag Manager](#google-tag-manager)
|
@@ -111,6 +112,27 @@ request.env['tracker'] = {
|
|
111
112
|
}
|
112
113
|
```
|
113
114
|
|
115
|
+
### Google Global Site Tag (gtag.js)
|
116
|
+
|
117
|
+
* `:anonymize_ip` - sets the tracker to remove the last octet from all IP addresses, see https://developers.google.com/analytics/devguides/collection/gtagjs/ip-anonymization for details.
|
118
|
+
* `:cookie_domain` - sets the domain name for the [GATC cookies](https://developers.google.com/analytics/devguides/collection/gtagjs/cookies-user-id). If not set its the website domain, with the www. prefix removed.
|
119
|
+
* `:user_id` - defines a proc to set the [userId](https://developers.google.com/analytics/devguides/collection/gtagjs/cookies-user-id). Ex: `user_id: lambda { |env| env['rack.session']['user_id'] }` would return the user_id from the session.
|
120
|
+
* `:link_attribution` - Enables [Enhanced Link Attribution](https://developers.google.com/analytics/devguides/collection/gtagjs/enhanced-link-attribution).
|
121
|
+
* `:allow_display_features` - Can be used to disable [Display Features](https://developers.google.com/analytics/devguides/collection/gtagjs/display-features).
|
122
|
+
* `:custom_map` - Used to [Configure and send custom dimensions](https://developers.google.com/analytics/devguides/collection/gtagjs/custom-dims-mets)
|
123
|
+
* `:set` - Used in the [set command to configure multiple properties](https://developers.google.com/analytics/devguides/collection/gtagjs/setting-values)
|
124
|
+
|
125
|
+
#### Trackers
|
126
|
+
|
127
|
+
Google Global Site tag allows configuring multiple trackers. Use the tracker option to configure the ids:
|
128
|
+
|
129
|
+
|
130
|
+
```ruby
|
131
|
+
config.middleware.use(Rack::Tracker) do
|
132
|
+
handler :google_global, { trackers: [ { id: 'U-XXXXX-Y' }, { id: 'U-WWWWWW-Z'} ] }
|
133
|
+
end
|
134
|
+
```
|
135
|
+
|
114
136
|
### Google Analytics
|
115
137
|
|
116
138
|
* `:anonymize_ip` - sets the tracker to remove the last octet from all IP addresses, see https://developers.google.com/analytics/devguides/collection/gajs/methods/gaJSApi_gat?hl=de#_gat._anonymizeIp for details.
|
data/lib/rack/tracker.rb
CHANGED
@@ -13,6 +13,7 @@ require "rack/tracker/handler"
|
|
13
13
|
require "rack/tracker/handler_delegator"
|
14
14
|
require "rack/tracker/controller"
|
15
15
|
require "rack/tracker/google_analytics/google_analytics"
|
16
|
+
require "rack/tracker/google_global/google_global"
|
16
17
|
require "rack/tracker/google_tag_manager/google_tag_manager"
|
17
18
|
require "rack/tracker/google_adwords_conversion/google_adwords_conversion"
|
18
19
|
require "rack/tracker/facebook/facebook"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Rack::Tracker::GoogleGlobal < Rack::Tracker::Handler
|
2
|
+
self.allowed_tracker_options = [:cookie_domain, :user_id,
|
3
|
+
:link_attribution, :allow_display_features, :anonymize_ip,
|
4
|
+
:custom_map]
|
5
|
+
|
6
|
+
class Page < OpenStruct
|
7
|
+
def params
|
8
|
+
Hash[to_h.slice(:title, :location, :path).map { |key, value| ["page_#{key}", value] }]
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def pages
|
13
|
+
events # TODO: Filter pages after Event is implemented
|
14
|
+
end
|
15
|
+
|
16
|
+
def trackers
|
17
|
+
options[:trackers].map { |tracker|
|
18
|
+
tracker[:id].respond_to?(:call) ? tracker.merge(id: tracker[:id].call(env)) : tracker
|
19
|
+
}.reject { |tracker| tracker[:id].nil? }
|
20
|
+
end
|
21
|
+
|
22
|
+
def set_options
|
23
|
+
@_set_options ||= build_set_options
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def build_set_options
|
29
|
+
value = options[:set]
|
30
|
+
value.respond_to?(:call) ? value.call(env) : value
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<% if trackers %>
|
2
|
+
<script async src='https://www.googletagmanager.com/gtag/js?id=<%= trackers[0][:id] %>'></script>
|
3
|
+
<script>
|
4
|
+
window.dataLayer = window.dataLayer || [];
|
5
|
+
function gtag(){dataLayer.push(arguments)};
|
6
|
+
gtag('js', new Date());
|
7
|
+
|
8
|
+
<% if set_options %>
|
9
|
+
gtag('set', <%= set_options.to_json %>);
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<% trackers.each do |tracker| %>
|
13
|
+
<% pages.each do |page| %>
|
14
|
+
gtag('config', '<%= tracker[:id] %>', <%= tracker_options.merge(page.params).to_json %>);
|
15
|
+
<% end %>
|
16
|
+
gtag('config', '<%= tracker[:id] %>', <%= tracker_options.to_json %>);
|
17
|
+
<% end %>
|
18
|
+
</script>
|
19
|
+
<% end %>
|
data/lib/rack/tracker/handler.rb
CHANGED
@@ -68,7 +68,8 @@ class Rack::Tracker::Handler
|
|
68
68
|
def tracker_options
|
69
69
|
@_tracker_options ||= {}.tap do |tracker_options|
|
70
70
|
options.slice(*allowed_tracker_options).each do |key, value|
|
71
|
-
|
71
|
+
option_value = value.respond_to?(:call) ? value.call(env) : value
|
72
|
+
unless option_value.nil?
|
72
73
|
tracker_options[tracker_option_key(key)] = tracker_option_value(option_value)
|
73
74
|
end
|
74
75
|
end
|
data/lib/rack/tracker/version.rb
CHANGED
@@ -0,0 +1,187 @@
|
|
1
|
+
RSpec.describe Rack::Tracker::GoogleGlobal do
|
2
|
+
def env
|
3
|
+
{
|
4
|
+
misc: 'foobar',
|
5
|
+
user_id: '123'
|
6
|
+
}
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'will be placed in the head' do
|
10
|
+
expect(described_class.position).to eq(:head)
|
11
|
+
expect(described_class.new(env).position).to eq(:head)
|
12
|
+
expect(described_class.new(env, position: :body).position).to eq(:body)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe '#tracker_options' do
|
16
|
+
context 'with an allowed option configured with a static value' do
|
17
|
+
subject { described_class.new(env, user_id: 'value') }
|
18
|
+
|
19
|
+
it 'returns hash with option set' do
|
20
|
+
expect(subject.tracker_options).to eql ({ user_id: 'value' })
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
context 'with an allowed option configured with a block' do
|
25
|
+
subject { described_class.new(env, user_id: lambda { |env| return env[:misc] }) }
|
26
|
+
|
27
|
+
it 'returns hash with option set' do
|
28
|
+
expect(subject.tracker_options).to eql ({ user_id: 'foobar' })
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'with an allowed option configured with a block returning nil' do
|
33
|
+
subject { described_class.new(env, user_id: lambda { |env| return env[:non_existing_key] }) }
|
34
|
+
|
35
|
+
it 'returns an empty hash' do
|
36
|
+
expect(subject.tracker_options).to eql ({})
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'with a non allowed option' do
|
41
|
+
subject { described_class.new(env, new_option: 'value') }
|
42
|
+
|
43
|
+
it 'returns an empty hash' do
|
44
|
+
expect(subject.tracker_options).to eql ({})
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#set_options' do
|
50
|
+
context 'with option configured with a static value' do
|
51
|
+
subject { described_class.new(env, set: { option: 'value' }) }
|
52
|
+
|
53
|
+
it 'returns hash with option set' do
|
54
|
+
expect(subject.set_options).to eql ({ option: 'value' })
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context 'with option configured with a block' do
|
59
|
+
subject { described_class.new(env, set: lambda { |env| return { option: env[:misc] } }) }
|
60
|
+
|
61
|
+
it 'returns hash with option set' do
|
62
|
+
expect(subject.set_options).to eql ({ option: 'foobar' })
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'with option configured with a block returning nil' do
|
67
|
+
subject { described_class.new(env, set: lambda { |env| return env[:non_existing_key] }) }
|
68
|
+
|
69
|
+
it 'returns nil' do
|
70
|
+
expect(subject.set_options).to be nil
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
describe "with custom domain" do
|
75
|
+
let(:tracker) { { id: 'somebody'}}
|
76
|
+
let(:options) { { cookie_domain: "railslabs.com", trackers: [tracker] } }
|
77
|
+
subject { described_class.new(env, options).render }
|
78
|
+
|
79
|
+
it "will show asyncronous tracker with cookie_domain" do
|
80
|
+
expect(subject).to match(%r{gtag\('config', 'somebody', {\"cookie_domain\":\"railslabs.com\"}\)})
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "with user_id tracking" do
|
85
|
+
let(:tracker) { { id: 'somebody'}}
|
86
|
+
let(:options) { { user_id: lambda { |env| return env[:user_id] }, trackers: [tracker] } }
|
87
|
+
subject { described_class.new(env, options).render }
|
88
|
+
|
89
|
+
it "will show asyncronous tracker with userId" do
|
90
|
+
expect(subject).to match(%r{gtag\('config', 'somebody', {\"user_id\":\"123\"}\)})
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "with link_attribution" do
|
95
|
+
let(:tracker) { { id: 'happy'}}
|
96
|
+
let(:options) { { link_attribution: true, trackers: [tracker] } }
|
97
|
+
subject { described_class.new(env, options).render }
|
98
|
+
|
99
|
+
it "will show asyncronous tracker with link_attribution" do
|
100
|
+
expect(subject).to match(%r{gtag\('config', 'happy', {\"link_attribution\":true}\)})
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe "with allow_display_features" do
|
105
|
+
let(:tracker) { { id: 'happy'}}
|
106
|
+
let(:options) { { allow_display_features: false, trackers: [tracker] } }
|
107
|
+
subject { described_class.new(env, options).render }
|
108
|
+
|
109
|
+
it "will disable display features" do
|
110
|
+
expect(subject).to match(%r{gtag\('config', 'happy', {\"allow_display_features\":false}\)})
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "with anonymizeIp" do
|
115
|
+
let(:tracker) { { id: 'happy'}}
|
116
|
+
let(:options) { { anonymize_ip: true, trackers: [tracker] } }
|
117
|
+
subject { described_class.new(env, options).render }
|
118
|
+
|
119
|
+
it "will set anonymizeIp to true" do
|
120
|
+
expect(subject).to match(%r{gtag\('config', 'happy', {\"anonymize_ip\":true}\)})
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "with dynamic tracker" do
|
125
|
+
let(:tracker) { { id: lambda { |env| return env[:misc] } }}
|
126
|
+
let(:options) { { trackers: [tracker] } }
|
127
|
+
subject { described_class.new(env, options).render }
|
128
|
+
|
129
|
+
it 'will call tracker lambdas to obtain tracking codes' do
|
130
|
+
expect(subject).to match(%r{gtag\('config', 'foobar', {}\)})
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe "with empty tracker" do
|
135
|
+
let(:present_tracker) { { id: 'present' }}
|
136
|
+
let(:empty_tracker) { { id: lambda { |env| return } }}
|
137
|
+
let(:options) { { trackers: [present_tracker, empty_tracker] } }
|
138
|
+
subject { described_class.new(env, options).render }
|
139
|
+
|
140
|
+
it 'will not render config' do
|
141
|
+
expect(subject).to match(%r{gtag\('config', 'present', {}\)})
|
142
|
+
expect(subject).not_to match(%r{gtag\('config', '', {}\)})
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe "with set options" do
|
147
|
+
let(:tracker) { { id: 'with_options' } }
|
148
|
+
let(:options) { { trackers: [tracker], set: { foo: 'bar' } } }
|
149
|
+
subject { described_class.new(env, options).render }
|
150
|
+
|
151
|
+
it 'will show set command' do
|
152
|
+
expect(subject).to match(%r{gtag\('set', {\"foo\":\"bar\"}\)})
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe "with virtual pages" do
|
157
|
+
subject { described_class.new(env, trackers: [{ id: 'somebody' }]).render }
|
158
|
+
|
159
|
+
describe "default" do
|
160
|
+
def env
|
161
|
+
{'tracker' => {
|
162
|
+
'google_global' => [
|
163
|
+
{ 'class_name' => 'Page', 'path' => '/virtual_page' }
|
164
|
+
]
|
165
|
+
}}
|
166
|
+
end
|
167
|
+
|
168
|
+
it "will show virtual page" do
|
169
|
+
expect(subject).to match(%r{gtag\('config', 'somebody', {\"page_path\":\"/virtual_page\"}\);})
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
describe "with a event value" do
|
174
|
+
def env
|
175
|
+
{'tracker' => {
|
176
|
+
'google_global' => [
|
177
|
+
{ 'class_name' => 'Page', 'path' => '/virtual_page', 'location' => 'https://example.com/virtual_page', 'title' => 'Virtual Page' }
|
178
|
+
]
|
179
|
+
}}
|
180
|
+
end
|
181
|
+
|
182
|
+
it "will show virtual page" do
|
183
|
+
expect(subject).to match(%r{gtag\('config', 'somebody', {\"page_title\":\"Virtual Page\",\"page_location\":\"https:\/\/example.com\/virtual_page\",\"page_path\":\"/virtual_page\"}\);})
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'support/capybara_app_helper'
|
2
|
+
|
3
|
+
RSpec.describe "Google Global Integration Integration" do
|
4
|
+
before do
|
5
|
+
setup_app(action: :google_global) do |tracker|
|
6
|
+
tracker.handler :google_global, trackers: [{ id: 'U-XXX-Y' }]
|
7
|
+
end
|
8
|
+
visit '/'
|
9
|
+
end
|
10
|
+
|
11
|
+
subject { page }
|
12
|
+
|
13
|
+
it "embeds the script tag with tracking event from the controller action" do
|
14
|
+
expect(page.find("head")).to have_content('U-XXX-Y')
|
15
|
+
end
|
16
|
+
|
17
|
+
describe 'adjust tracker position via options' do
|
18
|
+
before do
|
19
|
+
setup_app(action: :google_global) do |tracker|
|
20
|
+
tracker.handler :google_global, trackers: [{ id: 'U-XXX-Y' }], position: :body
|
21
|
+
end
|
22
|
+
visit '/'
|
23
|
+
end
|
24
|
+
|
25
|
+
it "will be placed in the specified tag" do
|
26
|
+
expect(page.find("head")).to_not have_content('U-XXX-Y')
|
27
|
+
expect(page.find("body")).to have_content('U-XXX-Y')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rack-tracker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lars Brillert
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2019-01-31 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rack
|
@@ -173,6 +173,8 @@ files:
|
|
173
173
|
- lib/rack/tracker/google_adwords_conversion/template/google_adwords_conversion.erb
|
174
174
|
- lib/rack/tracker/google_analytics/google_analytics.rb
|
175
175
|
- lib/rack/tracker/google_analytics/template/google_analytics.erb
|
176
|
+
- lib/rack/tracker/google_global/google_global.rb
|
177
|
+
- lib/rack/tracker/google_global/template/google_global.erb
|
176
178
|
- lib/rack/tracker/google_tag_manager/google_tag_manager.rb
|
177
179
|
- lib/rack/tracker/google_tag_manager/template/google_tag_manager_body.erb
|
178
180
|
- lib/rack/tracker/google_tag_manager/template/google_tag_manager_head.erb
|
@@ -201,6 +203,7 @@ files:
|
|
201
203
|
- spec/handler/go_squared_spec.rb
|
202
204
|
- spec/handler/google_adwords_conversion_spec.rb
|
203
205
|
- spec/handler/google_analytics_spec.rb
|
206
|
+
- spec/handler/google_global_spec.rb
|
204
207
|
- spec/handler/google_tag_manager_spec.rb
|
205
208
|
- spec/handler/handler_spec.rb
|
206
209
|
- spec/handler/hotjar_spec.rb
|
@@ -212,6 +215,7 @@ files:
|
|
212
215
|
- spec/integration/go_squared_integration_spec.rb
|
213
216
|
- spec/integration/google_adwords_conversion_integration_spec.rb
|
214
217
|
- spec/integration/google_analytics_integration_spec.rb
|
218
|
+
- spec/integration/google_global_integration_spec.rb
|
215
219
|
- spec/integration/google_tag_manager_integration_spec.rb
|
216
220
|
- spec/integration/hotjar_integration_spec.rb
|
217
221
|
- spec/integration/rails_integration_spec.rb
|
@@ -246,7 +250,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
246
250
|
version: '0'
|
247
251
|
requirements: []
|
248
252
|
rubyforge_project:
|
249
|
-
rubygems_version: 2.7.
|
253
|
+
rubygems_version: 2.7.7
|
250
254
|
signing_key:
|
251
255
|
specification_version: 4
|
252
256
|
summary: Tracking made easy
|
@@ -264,6 +268,7 @@ test_files:
|
|
264
268
|
- spec/handler/go_squared_spec.rb
|
265
269
|
- spec/handler/google_adwords_conversion_spec.rb
|
266
270
|
- spec/handler/google_analytics_spec.rb
|
271
|
+
- spec/handler/google_global_spec.rb
|
267
272
|
- spec/handler/google_tag_manager_spec.rb
|
268
273
|
- spec/handler/handler_spec.rb
|
269
274
|
- spec/handler/hotjar_spec.rb
|
@@ -275,6 +280,7 @@ test_files:
|
|
275
280
|
- spec/integration/go_squared_integration_spec.rb
|
276
281
|
- spec/integration/google_adwords_conversion_integration_spec.rb
|
277
282
|
- spec/integration/google_analytics_integration_spec.rb
|
283
|
+
- spec/integration/google_global_integration_spec.rb
|
278
284
|
- spec/integration/google_tag_manager_integration_spec.rb
|
279
285
|
- spec/integration/hotjar_integration_spec.rb
|
280
286
|
- spec/integration/rails_integration_spec.rb
|