diff --git a/README.md b/README.md index 4385559..b4289d3 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: 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). diff --git a/lib/rack/tracker/google_analytics/google_analytics.rb b/lib/rack/tracker/google_analytics/google_analytics.rb index 9ca7f19..58965e9 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') @@ -28,6 +31,18 @@ def tracker options[:tracker].respond_to?(:call) ? options[:tracker].call(env) : options[:tracker] end + def tracker_options + @tracker_options ||= begin + tracker_options = {} + options.slice(*ALLOWED_TRACKER_OPTIONS).each do |key, value| + if option_value = value.respond_to?(:call) ? value.call(env) : value + tracker_options["#{key}".camelize(:lower).to_sym] = "#{option_value}" + end + end + 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/spec/handler/google_analytics_spec.rb b/spec/handler/google_analytics_spec.rb index 67a67b8..6960d4a 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 @@ -30,6 +33,44 @@ def env end end + describe '#tracker_options' do + before do + stub_const("#{described_class}::ALLOWED_TRACKER_OPTIONS", [:some_option]) + end + + context 'with an allowed option configured with a static value' do + subject { described_class.new(env, { some_option: 'value' }) } + + it 'returns hash with option set' do + expect(subject.tracker_options).to eql ({ someOption: 'value' }) + end + end + + 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 option set' do + expect(subject.tracker_options).to eql ({ someOption: 'foobar' }) + 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' }) } + + it 'returns an empty hash' do + expect(subject.tracker_options).to eql ({}) + end + end + end + describe "with events" do describe "default" do def env @@ -93,6 +134,15 @@ def env end end + describe "with user_id tracking" do + 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\"}\)}) + 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 }