From 28d59f2cbcbe9a21a87568564b131c431a2dbefc Mon Sep 17 00:00:00 2001 From: Salim Hbeiliny Date: Wed, 21 Jan 2015 14:50:38 +0100 Subject: [PATCH 1/6] add support for google analytics userId See: https://developers.google.com/analytics/devguides/collection/analyticsjs /user-id --- CHANGELOG.md | 4 ++ README.md | 1 + .../google_analytics/google_analytics.rb | 13 +++++++ .../template/google_analytics.erb | 2 +- lib/rack/tracker/version.rb | 2 +- spec/handler/google_analytics_spec.rb | 37 +++++++++++++++++++ 6 files changed, 57 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 18bfef0..f8ec985 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.3.1 + + * [ENHANCEMENT] add support for google analytics userId + # 0.3.0 * [ENHANCEMENT] google analytics cookieDomain renamed to cookie_domain diff --git a/README.md b/README.md index 4385559..670b23a 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ request.env['tracker'] = { * `: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. * `:cookie_domain` - sets the domain name for the GATC cookies. Defaults to `auto`. +* `:user_id` - defines a proc to set the [userId](https://developers.google.com/analytics/devguides/collection/analyticsjs/user-id). Ex: `user_id: ->(env) { env['rack.session']['user_id'] }` would return the user_id from the session. * `:site_speed_sample_rate` - Defines a new sample set size for Site Speed data collection, see https://developers.google.com/analytics/devguides/collection/gajs/methods/gaJSApiBasicConfiguration?hl=de#_gat.GA_Tracker_._setSiteSpeedSampleRate * `:adjusted_bounce_rate_timeouts` - An array of times in seconds that the tracker will use to set timeouts for adjusted bounce rate tracking. See http://analytics.blogspot.ca/2012/07/tracking-adjusted-bounce-rate-in-google.html for details. * `:enhanced_link_attribution` - Enables [Enhanced Link Attribution](https://developers.google.com/analytics/devguides/collection/analyticsjs/advanced#enhancedlink). diff --git a/lib/rack/tracker/google_analytics/google_analytics.rb b/lib/rack/tracker/google_analytics/google_analytics.rb index 9ca7f19..3f15287 100644 --- a/lib/rack/tracker/google_analytics/google_analytics.rb +++ b/lib/rack/tracker/google_analytics/google_analytics.rb @@ -28,6 +28,19 @@ def tracker options[:tracker].respond_to?(:call) ? options[:tracker].call(env) : options[:tracker] end + def tracker_options + @tracker_options ||= begin + tracker_options = {} + + tracker_options[:cookieDomain] = options[:cookie_domain] if options[:cookie_domain] + + user_id = options[:user_id].call(env) if options[:user_id] + tracker_options[:userId] = "#{user_id}" if user_id.present? + + tracker_options + end + end + def render Tilt.new( File.join( File.dirname(__FILE__), 'template', 'google_analytics.erb') ).render(self) end diff --git a/lib/rack/tracker/google_analytics/template/google_analytics.erb b/lib/rack/tracker/google_analytics/template/google_analytics.erb index 4a2ccdb..511e5d5 100644 --- a/lib/rack/tracker/google_analytics/template/google_analytics.erb +++ b/lib/rack/tracker/google_analytics/template/google_analytics.erb @@ -7,7 +7,7 @@ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - ga('create', '<%= tracker %>', <%= (options[:cookie_domain] ? {cookieDomain: options[:cookie_domain]} : {}).to_json %>); + ga('create', '<%= tracker %>', <%= tracker_options.to_json %>); } <% if options[:enhanced_link_attribution] %> diff --git a/lib/rack/tracker/version.rb b/lib/rack/tracker/version.rb index db626a3..e899b3d 100644 --- a/lib/rack/tracker/version.rb +++ b/lib/rack/tracker/version.rb @@ -1,5 +1,5 @@ module Rack class Tracker - VERSION = '0.3.0' + VERSION = '0.3.1' end end diff --git a/spec/handler/google_analytics_spec.rb b/spec/handler/google_analytics_spec.rb index 67a67b8..2f5496c 100644 --- a/spec/handler/google_analytics_spec.rb +++ b/spec/handler/google_analytics_spec.rb @@ -30,6 +30,34 @@ def env end end + describe '#tracker_options' do + describe 'with cookie_domain option' do + subject { described_class.new(env, { cookie_domain: 'railslabs.com' }) } + + it 'returns hash with cookieDomain' do + expect(subject.tracker_options).to eql ({ cookieDomain: 'railslabs.com' }) + end + end + + describe 'with user_id option' do + context 'returning a value' do + subject { described_class.new(env, { user_id: ->(env){ '123' } }) } + + it 'returns hash with userId' do + expect(subject.tracker_options).to eql ({ userId: '123' }) + end + end + + context 'returning nil' do + subject { described_class.new(env, { user_id: ->(env){ nil } }) } + + it 'returns hash without userId' do + expect(subject.tracker_options).to eql ({ }) + end + end + end + end + describe "with events" do describe "default" do def env @@ -93,6 +121,15 @@ def env end end + describe "with user_id tracking" do + subject { described_class.new(env, tracker: 'somebody', user_id: ->(env){ '123' } ).render } + + it "will show asyncronous tracker with userId" do + expect(subject).to match(%r{ga\('create', 'somebody', {\"userId\":\"123\"}\)}) + expect(subject).to match(%r{ga\('send', 'pageview'\)}) + end + end + describe "with enhanced_link_attribution" do subject { described_class.new(env, tracker: 'happy', enhanced_link_attribution: true).render } From 621731f06f99c0d48260285ef99bc0beb3b89f4c Mon Sep 17 00:00:00 2001 From: Salim Hbeiliny Date: Thu, 22 Jan 2015 14:22:11 +0100 Subject: [PATCH 2/6] revert version bumping --- CHANGELOG.md | 4 ---- lib/rack/tracker/version.rb | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f8ec985..18bfef0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,3 @@ -# 0.3.1 - - * [ENHANCEMENT] add support for google analytics userId - # 0.3.0 * [ENHANCEMENT] google analytics cookieDomain renamed to cookie_domain diff --git a/lib/rack/tracker/version.rb b/lib/rack/tracker/version.rb index e899b3d..db626a3 100644 --- a/lib/rack/tracker/version.rb +++ b/lib/rack/tracker/version.rb @@ -1,5 +1,5 @@ module Rack class Tracker - VERSION = '0.3.1' + VERSION = '0.3.0' end end From 17000d348411e38d989e90e7bc705d22f4b05dad Mon Sep 17 00:00:00 2001 From: Salim Hbeiliny Date: Thu, 22 Jan 2015 15:38:07 +0100 Subject: [PATCH 3/6] more generic tracker_options --- .../google_analytics/google_analytics.rb | 19 ++++++++---- spec/handler/google_analytics_spec.rb | 30 ++++++++++--------- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/lib/rack/tracker/google_analytics/google_analytics.rb b/lib/rack/tracker/google_analytics/google_analytics.rb index 3f15287..cfd7efd 100644 --- a/lib/rack/tracker/google_analytics/google_analytics.rb +++ b/lib/rack/tracker/google_analytics/google_analytics.rb @@ -1,4 +1,7 @@ class Rack::Tracker::GoogleAnalytics < Rack::Tracker::Handler + + ALLOWED_TRACKER_OPTIONS = [:cookie_domain, :user_id] + class Send < OpenStruct def initialize(attrs = {}) attrs.reverse_merge!(type: 'event') @@ -31,12 +34,16 @@ def tracker def tracker_options @tracker_options ||= begin tracker_options = {} - - tracker_options[:cookieDomain] = options[:cookie_domain] if options[:cookie_domain] - - user_id = options[:user_id].call(env) if options[:user_id] - tracker_options[:userId] = "#{user_id}" if user_id.present? - + ALLOWED_TRACKER_OPTIONS.each do |option| + if options[option] + if options[option].respond_to?(:call) + option_value = options[option].call(env) + else + option_value = options[option] + end + end + tracker_options["#{option}".camelize(:lower).to_sym] = "#{option_value}" if option_value.present? + end tracker_options end end diff --git a/spec/handler/google_analytics_spec.rb b/spec/handler/google_analytics_spec.rb index 2f5496c..01d8666 100644 --- a/spec/handler/google_analytics_spec.rb +++ b/spec/handler/google_analytics_spec.rb @@ -31,29 +31,31 @@ def env end describe '#tracker_options' do - describe 'with cookie_domain option' do - subject { described_class.new(env, { cookie_domain: 'railslabs.com' }) } + before do + stub_const("#{described_class}::ALLOWED_TRACKER_OPTIONS", [:some_option]) + end + + context 'an allowed option configured with a static value' do + subject { described_class.new(env, { some_option: 'value' }) } it 'returns hash with cookieDomain' do - expect(subject.tracker_options).to eql ({ cookieDomain: 'railslabs.com' }) + expect(subject.tracker_options).to eql ({ someOption: 'value' }) end end - describe 'with user_id option' do - context 'returning a value' do - subject { described_class.new(env, { user_id: ->(env){ '123' } }) } + context 'an allowed option configured with a block' do + subject { described_class.new(env, { some_option: ->(env){ 'value' } }) } - it 'returns hash with userId' do - expect(subject.tracker_options).to eql ({ userId: '123' }) - end + it 'returns hash with cookieDomain' do + expect(subject.tracker_options).to eql ({ someOption: 'value' }) end + end - context 'returning nil' do - subject { described_class.new(env, { user_id: ->(env){ nil } }) } + context 'a non allowed option' do + subject { described_class.new(env, { new_option: 'value' }) } - it 'returns hash without userId' do - expect(subject.tracker_options).to eql ({ }) - end + it 'returns hash with cookieDomain' do + expect(subject.tracker_options).to eql ({}) end end end From e1b0f9e3280055b033a643d7337614632a485b80 Mon Sep 17 00:00:00 2001 From: Salim Hbeiliny Date: Thu, 22 Jan 2015 17:57:00 +0100 Subject: [PATCH 4/6] refactor ga tracker_options method * remove one if * refactor spec --- .../google_analytics/google_analytics.rb | 14 +++++------ spec/handler/google_analytics_spec.rb | 23 +++++++++++-------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/lib/rack/tracker/google_analytics/google_analytics.rb b/lib/rack/tracker/google_analytics/google_analytics.rb index cfd7efd..5faa9e4 100644 --- a/lib/rack/tracker/google_analytics/google_analytics.rb +++ b/lib/rack/tracker/google_analytics/google_analytics.rb @@ -34,15 +34,13 @@ def tracker def tracker_options @tracker_options ||= begin tracker_options = {} - ALLOWED_TRACKER_OPTIONS.each do |option| - if options[option] - if options[option].respond_to?(:call) - option_value = options[option].call(env) - else - option_value = options[option] - end + options.slice(*ALLOWED_TRACKER_OPTIONS).each do |key, value| + if value.respond_to?(:call) + option_value = value.call(env) + else + option_value = value end - tracker_options["#{option}".camelize(:lower).to_sym] = "#{option_value}" if option_value.present? + tracker_options["#{key}".camelize(:lower).to_sym] = "#{option_value}" if option_value.present? end tracker_options end diff --git a/spec/handler/google_analytics_spec.rb b/spec/handler/google_analytics_spec.rb index 01d8666..23b4fea 100644 --- a/spec/handler/google_analytics_spec.rb +++ b/spec/handler/google_analytics_spec.rb @@ -1,7 +1,10 @@ RSpec.describe Rack::Tracker::GoogleAnalytics do def env - {misc: 'foobar'} + { + misc: 'foobar', + user_id: '123' + } end it 'will be placed in the head' do @@ -35,26 +38,26 @@ def env stub_const("#{described_class}::ALLOWED_TRACKER_OPTIONS", [:some_option]) end - context 'an allowed option configured with a static value' do + context 'with an allowed option configured with a static value' do subject { described_class.new(env, { some_option: 'value' }) } - it 'returns hash with cookieDomain' do + it 'returns hash with option set' do expect(subject.tracker_options).to eql ({ someOption: 'value' }) end end - context 'an allowed option configured with a block' do - subject { described_class.new(env, { some_option: ->(env){ 'value' } }) } + context 'with an allowed option configured with a block' do + subject { described_class.new(env, { some_option: lambda { |env| return env[:misc] } }) } - it 'returns hash with cookieDomain' do - expect(subject.tracker_options).to eql ({ someOption: 'value' }) + it 'returns hash with option set' do + expect(subject.tracker_options).to eql ({ someOption: 'foobar' }) end end - context 'a non allowed option' do + context 'with a non allowed option' do subject { described_class.new(env, { new_option: 'value' }) } - it 'returns hash with cookieDomain' do + it 'returns an empty hash' do expect(subject.tracker_options).to eql ({}) end end @@ -124,7 +127,7 @@ def env end describe "with user_id tracking" do - subject { described_class.new(env, tracker: 'somebody', user_id: ->(env){ '123' } ).render } + subject { described_class.new(env, tracker: 'somebody', user_id: lambda { |env| return env[:user_id] } ).render } it "will show asyncronous tracker with userId" do expect(subject).to match(%r{ga\('create', 'somebody', {\"userId\":\"123\"}\)}) From af6492366bfc25bbb8f365cb7797f1ee6ba18c30 Mon Sep 17 00:00:00 2001 From: Salim Hbeiliny Date: Thu, 22 Jan 2015 18:00:31 +0100 Subject: [PATCH 5/6] update readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 670b23a..b4289d3 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ request.env['tracker'] = { * `: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. * `:cookie_domain` - sets the domain name for the GATC cookies. Defaults to `auto`. -* `:user_id` - defines a proc to set the [userId](https://developers.google.com/analytics/devguides/collection/analyticsjs/user-id). Ex: `user_id: ->(env) { env['rack.session']['user_id'] }` would return the user_id from the session. +* `:user_id` - defines a proc to set the [userId](https://developers.google.com/analytics/devguides/collection/analyticsjs/user-id). Ex: `user_id: lambda { |env| env['rack.session']['user_id'] }` would return the user_id from the session. * `:site_speed_sample_rate` - Defines a new sample set size for Site Speed data collection, see https://developers.google.com/analytics/devguides/collection/gajs/methods/gaJSApiBasicConfiguration?hl=de#_gat.GA_Tracker_._setSiteSpeedSampleRate * `:adjusted_bounce_rate_timeouts` - An array of times in seconds that the tracker will use to set timeouts for adjusted bounce rate tracking. See http://analytics.blogspot.ca/2012/07/tracking-adjusted-bounce-rate-in-google.html for details. * `:enhanced_link_attribution` - Enables [Enhanced Link Attribution](https://developers.google.com/analytics/devguides/collection/analyticsjs/advanced#enhancedlink). From ba3af1828fcafe843f35ce5be887b596d4a279ed Mon Sep 17 00:00:00 2001 From: Salim Hbeiliny Date: Fri, 23 Jan 2015 11:32:54 +0100 Subject: [PATCH 6/6] ga allowed_options: more refactoring and spec when a proc returning nil is given --- lib/rack/tracker/google_analytics/google_analytics.rb | 7 ++----- spec/handler/google_analytics_spec.rb | 8 ++++++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/rack/tracker/google_analytics/google_analytics.rb b/lib/rack/tracker/google_analytics/google_analytics.rb index 5faa9e4..58965e9 100644 --- a/lib/rack/tracker/google_analytics/google_analytics.rb +++ b/lib/rack/tracker/google_analytics/google_analytics.rb @@ -35,12 +35,9 @@ def tracker_options @tracker_options ||= begin tracker_options = {} options.slice(*ALLOWED_TRACKER_OPTIONS).each do |key, value| - if value.respond_to?(:call) - option_value = value.call(env) - else - option_value = value + if option_value = value.respond_to?(:call) ? value.call(env) : value + tracker_options["#{key}".camelize(:lower).to_sym] = "#{option_value}" end - tracker_options["#{key}".camelize(:lower).to_sym] = "#{option_value}" if option_value.present? end tracker_options end diff --git a/spec/handler/google_analytics_spec.rb b/spec/handler/google_analytics_spec.rb index 23b4fea..6960d4a 100644 --- a/spec/handler/google_analytics_spec.rb +++ b/spec/handler/google_analytics_spec.rb @@ -54,6 +54,14 @@ def env end end + context 'with an allowed option configured with a block returning nil' do + subject { described_class.new(env, { some_option: lambda { |env| return env[:non_existing_key] } }) } + + it 'returns an empty hash' do + expect(subject.tracker_options).to eql ({}) + end + end + context 'with a non allowed option' do subject { described_class.new(env, { new_option: 'value' }) }