rack-tracker 1.7.0 → 1.8.0

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
2
  SHA256:
3
- metadata.gz: 55705dd46c88e815dd7b0187c3d6d2a50b36a79f5ccc52e801a96d282ba348be
4
- data.tar.gz: 5cad1746a043405f4f0e1b2cf85904dd9a6daa50923199d77d71bb32b7a357ba
3
+ metadata.gz: e9d098ca10113dc7340ab5e268dec40e8b0143a0d1284d1caaeac155510c1bd6
4
+ data.tar.gz: c84e057fd1021e504ff749fd5a70e3a79ced5343d39720af987fb5b3783a38b3
5
5
  SHA512:
6
- metadata.gz: 0ea613048f9899f3c532eee40c7dd40ed9e4c6c6623f318df1522bbb11e3a05656bb3b96adf0b3b46bd10e33c34f9ab5774c7d48402e1830e3efff2042b144e2
7
- data.tar.gz: ea8b57893ebdcc970e55085f20cefc4cdb1e18f5172b6e44cc3c54a2189335109cafe0694e30854edaa90ed3f3d8330051dc2619b7826f3a5180cb168ea129d3
6
+ metadata.gz: 4a140e3e30f813d916adec3e6a6aed6919b53d72281d2880ae81ecc035d980c9c330fce2b0bd85497bb92e20172db0aa5bffa8edd0e9fd538f15380be66124aa
7
+ data.tar.gz: 357e0828908134f96ed5370554b17d9ecdce43a098493471dc9a5807e1af7f186ce05bb7a5674ac2f36a0f6eddefdf93742be93f8682573266065bd368c087d6
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ # 1.8.0
2
+
3
+ * [ENHANCEMENT] Google Global Site Tag: basic integration with support for pageviews to Google global tag #123 (thx @atd)
4
+
1
5
  # 1.7.0
2
6
 
3
7
  * [BUGFIX] dup response string in Rack::Tracker#inject to avoid RuntimeError #114 (thx @zpfled)
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 %>
@@ -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
- if option_value = value.respond_to?(:call) ? value.call(env) : value
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
@@ -1,5 +1,5 @@
1
1
  module Rack
2
2
  class Tracker
3
- VERSION = '1.7.0'
3
+ VERSION = '1.8.0'
4
4
  end
5
5
  end
@@ -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
@@ -61,6 +61,10 @@ class MetalController < ActionController::Metal
61
61
  render "metal/index"
62
62
  end
63
63
 
64
+ def google_global
65
+ render "metal/index"
66
+ end
67
+
64
68
  def google_tag_manager
65
69
  unless params[:no_events]
66
70
  tracker do |t|
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.7.0
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: 2018-07-19 00:00:00.000000000 Z
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.6
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