ua-google-analytics-rails 1.0.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.
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+
3
+ require 'json'
4
+
5
+ module GoogleAnalytics
6
+ class EventRenderer
7
+ def initialize(event, tracker_id)
8
+ @event = event
9
+ @tracker_id = tracker_id
10
+ end
11
+
12
+ def to_s
13
+ if @event.class.name == 'GoogleAnalytics::Events::SetupAnalytics'
14
+ "ga('#{@event.action}',#{array_to_json([@event.name, *@event.params])});"
15
+ elsif @event.single_event?
16
+ "ga('#{@tracker_id ? [@tracker_id, @event.action].join('.') : @event.action}');"
17
+ else
18
+ "ga('#{@tracker_id ? [@tracker_id, @event.action].join('.') : @event.action}',#{array_to_json([@event.name, *@event.params])});"
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def array_to_json(array)
25
+ array.map {|string| string_to_json(string) } .join(',')
26
+ end
27
+
28
+ def string_to_json(string)
29
+ # replace double quotes with single ones
30
+ string.to_json.gsub(/^"/, "'").gsub(/"$/, "'")
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,230 @@
1
+ # coding: utf-8
2
+
3
+ module GoogleAnalytics
4
+ module Events
5
+ class SetupAnalytics < Event
6
+
7
+ def initialize(account_id, opts={})
8
+ if ['auto','none'].include?(opts) || opts.empty?
9
+ super('create', account_id, opts.empty? ? 'auto' : opts)
10
+ elsif opts.is_a?(Hash)
11
+ super('create', account_id, attributes_hash(opts))
12
+ else
13
+ super('create', account_id, {:cookieDomain => opts})
14
+ end
15
+ end
16
+
17
+ private
18
+ def attributes_hash(opts={})
19
+ {
20
+ :cookieDomain => opts.delete(:cookieDomain) || 'auto',
21
+ :allowLinker => opts.delete(:allowLinker),
22
+ :cookieName => opts.delete(:cookieName),
23
+ :cookieExpires => opts.delete(:cookieExpires),
24
+ :sampleRate => opts.delete(:sampleRate),
25
+ :siteSpeedSampleRate => opts.delete(:siteSpeedSampleRate),
26
+ :name => opts.delete(:name)
27
+ }.reject{|k,v| !v }
28
+ end
29
+ end
30
+
31
+ class SetAccount
32
+ def initialize(account_id)
33
+ warn "[REMOVED] `SetAccount` is being removed. Universal Analytics does not support this any longer. Please see GoogleAnalytics::Events::SetupAnalytics"
34
+ end
35
+ end
36
+
37
+ class SetDomainName
38
+ def initialize(domain_name)
39
+ warn "[REMOVED] `SetDomainName` is being removed. Universal Analytics does not support this any longer. Please see GoogleAnalytics::Events::SetupAnalytics"
40
+ end
41
+ end
42
+
43
+ class SetAllowLinker
44
+ def initialize(allow)
45
+ warn "[REMOVED] `SetAllowLinker` is being removed. Universal Analytics does not support this any longer. Please see GoogleAnalytics::Events::SetupAnalytics"
46
+ end
47
+ end
48
+
49
+ class Require < Event
50
+ def initialize(name, url=nil)
51
+ if url
52
+ super('require', name, url)
53
+ else
54
+ super('require', name)
55
+ end
56
+ end
57
+ end
58
+
59
+ class SetSiteSpeedSampleRate
60
+ # @param sample_rate [Integer] the percentage of page views that should be used
61
+ # for page speed metrics - defaults to 1 (aka 1%) if the event is missing.
62
+ attr_accessor :sample_rate
63
+ def initialize(sample_rate)
64
+ @sample_rate = sample_rate
65
+ warn "[REMOVED] `SetSiteSpeedSampleRate` is being removed. Universal Analytics does not support this any longer. Please see GoogleAnalytics::Events::SetupAnalytics"
66
+ end
67
+ end
68
+
69
+ # http://misterphilip.com/universal-analytics/migration/basics
70
+ class TrackPageview < Event
71
+ # @param page [String] optional virtual pageview tracking
72
+ # @see http://code.google.com/apis/analytics/docs/tracking/asyncMigrationExamples.html#VirtualPageviews
73
+ def initialize(opts = {})
74
+ # Just use default pageview if no page was given
75
+ if opts.is_a?(Hash) && opts.fetch(:page, nil) == nil
76
+ super('send', 'pageview')
77
+ # Provide only the page string if a title was not given but a page was
78
+ elsif opts.is_a?(Hash) && opts.fetch(:page, false)
79
+ super('send', 'pageview', opts.fetch(:title, false) ? opts : opts[:page])
80
+ # Print out a JSON Value for the pageview
81
+ else
82
+ super('send', 'pageview', opts)
83
+ end
84
+ end
85
+ end
86
+
87
+ class TrackEvent < Event
88
+ def initialize(category, action, label = nil, value = nil)
89
+ if label || value
90
+ super('send', 'event', category.to_s, action.to_s, label ? label.to_s : nil, value ? value.to_i : nil)
91
+ else
92
+ super('send', 'event', category.to_s, action.to_s)
93
+ end
94
+ end
95
+ end
96
+
97
+ class ExperimentId < Event
98
+ def initialize(id)
99
+ super('set', 'expId', id.to_s)
100
+ end
101
+ end
102
+
103
+ class ExperimentVariation < Event
104
+ def initialize(variation_id)
105
+ super('set', 'expVar', variation_id.to_i)
106
+ end
107
+ end
108
+
109
+ # Custom Vars no longer exist in Universal Analytics
110
+ # Transfer to dimensions & metrics
111
+ # ga('set', 'dimension1', 953);
112
+ # ga('set', 'metric5', 953);
113
+ #
114
+
115
+ # Deprecated: Please use `SetCustomDimension` or `SetCustomMetric` instead
116
+ #
117
+ class SetCustomVar < Event
118
+ def initialize(index, name, value, opt_scope)
119
+ raise ArgumentError, "The index has to be between 1 and 5" unless (1..5).include?(index.to_i)
120
+ warn "[DEPRECATION] `SetCustomVar` is deprecated. Please use `SetCustomDimension` or `SetCustomMetric` instead"
121
+ super('set', "dimension#{index}", value.to_s)
122
+ end
123
+ end
124
+
125
+ class SetCustomDimension < Event
126
+ def initialize(index, value)
127
+ raise ArgumentError, "The index has to be between 1 and 5" unless (1..5).include?(index.to_i)
128
+ super('set', "dimension#{index}", value.to_s)
129
+ end
130
+ end
131
+ class SetCustomMetric < Event
132
+ def initialize(index, value)
133
+ raise ArgumentError, "The index has to be between 1 and 5" unless (1..5).include?(index.to_i)
134
+ super('set', "metric#{index}", value.to_s)
135
+ end
136
+ end
137
+
138
+ # Removed: There are no longer Custom Variables
139
+ class DeleteCustomVar < Event
140
+ def initialize(index)
141
+ warn "[REMOVED] `DeleteCustomVar` is being removed. Universal Analytics does not support Custom Variables."
142
+ end
143
+ end
144
+
145
+ # @see https://developers.google.com/analytics/devguides/collection/gajs/methods/gaJSApi_gat#_gat._anonymizeIp
146
+ #
147
+ # Anonymize the visitor IP address. This seems to be mandatory for European websites and actively enforced
148
+ # for German ones.
149
+ #
150
+ # See the following comment by Roland Moriz for more information:
151
+ # https://github.com/bgarret/google-analytics-rails/pull/6#issuecomment-5946066
152
+ #
153
+ # JavaScript equivalent:
154
+ #
155
+ # ga('set', 'anonymizeIp', true);
156
+ #
157
+ class AnonymizeIp < Event
158
+ def initialize
159
+ super('set', 'anonymizeIp', true)
160
+ end
161
+ end
162
+
163
+ # @see http://code.google.com/apis/analytics/docs/tracking/gaTrackingEcommerce.html
164
+ module Ecommerce
165
+ # JavaScript equivalent:
166
+ #
167
+ # ga('ecommerce:addTransaction', {
168
+ # 'id': '1234',
169
+ # 'affiliation': 'Acme Clothing',
170
+ # 'revenue': '11.99',
171
+ # 'shipping': '5',
172
+ # 'tax': '1.29',
173
+ # 'currency': 'EUR' // local currency code.
174
+ # });
175
+ #
176
+ class AddTransaction < Event
177
+ def initialize(order_id, store_name, total, tax, shipping, city=nil, state_or_province=nil, country=nil)
178
+ # city.to_s, state_or_province.to_s, country.to_s
179
+
180
+ super('ecommerce:addTransaction', {
181
+ :id => order_id.to_s,
182
+ :affiliation => store_name.to_s,
183
+ :revenue => total.to_s,
184
+ :tax => tax.to_s,
185
+ :shipping => shipping.to_s
186
+ })
187
+ end
188
+ end
189
+
190
+ # JavaScript equivalent:
191
+ #
192
+ # _gaq.push(['_addItem',
193
+ # '1234', // order ID - required
194
+ # 'DD44', // SKU/code - required
195
+ # 'T-Shirt', // product name
196
+ # 'Green Medium', // category or variation
197
+ # '11.99', // unit price - required
198
+ # '1' // quantity - required
199
+ # ]);
200
+ #
201
+ class AddItem < Event
202
+ def initialize(order_id, product_id, product_name, product_variation, unit_price, quantity)
203
+ super('ecommerce:addItem', {
204
+ :id => order_id.to_s,
205
+ :sku => product_id.to_s,
206
+ :name => product_name.to_s,
207
+ :category => product_variation.to_s,
208
+ :price => unit_price.to_s,
209
+ :quantity => quantity.to_s
210
+ })
211
+ end
212
+ end
213
+
214
+ # JavaScript equivalent:
215
+ #
216
+ # ga('ecommerce:send');
217
+ #
218
+ class TrackTransaction < SingleEvent
219
+ def initialize
220
+ super('ecommerce:send')
221
+ end
222
+ end
223
+ class ClearTransaction < SingleEvent
224
+ def initialize
225
+ super('ecommerce:clear')
226
+ end
227
+ end
228
+ end
229
+ end
230
+ end
@@ -0,0 +1,12 @@
1
+ # coding: utf-8
2
+
3
+ require 'google-analytics/rails/view_helpers'
4
+
5
+ module GoogleAnalytics::Rails
6
+ # @private
7
+ class Railtie < ::Rails::Railtie
8
+ initializer "google-analytics-rails" do
9
+ ActionView::Base.send :include, ViewHelpers
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,208 @@
1
+ # coding: utf-8
2
+
3
+ require 'active_support/core_ext/string/output_safety'
4
+ require 'active_support/core_ext/object/blank'
5
+
6
+ module GoogleAnalytics::Rails
7
+ # All the helper methods output raw javascript with single quoted strings. This allows more flexbility in choosing when the event gets sent (on page load, on user action, etc).
8
+ #
9
+ # The only exception is {#analytics_init}, which is wrapped in a `<script>` tag.
10
+ #
11
+ # @example This event is always sent on page load
12
+ #
13
+ # <script>
14
+ # <%= analytics_track_event "Videos", "Play", "Gone With the Wind" %>
15
+ # </script>
16
+ #
17
+ # @example This event is sent when the visitor clicks on the link
18
+ #
19
+ # # note the double quotes around the onclick attribute,
20
+ # # they are necessary because the javascript is single quoted
21
+ # <a href="my_url" onclick="<%= analytics_track_event "Videos", "Play", "Gone With the Wind" %>">Link</a>
22
+ #
23
+ # @example Full ecommerce example
24
+ #
25
+ # # create a new transaction
26
+ # analytics_add_transaction(
27
+ # '1234', # order ID - required
28
+ # 'Acme Clothing', # affiliation or store name
29
+ # '11.99', # total - required
30
+ # '1.29', # tax
31
+ # '5' # shipping
32
+ # )
33
+ #
34
+ # # add an item to the transaction
35
+ # analytics_add_item(
36
+ # '1234', # order ID - required
37
+ # 'DD44', # SKU/code - required
38
+ # 'T-Shirt', # product name
39
+ # 'Green Medium', # category or variation
40
+ # '11.99', # unit price - required
41
+ # '1' # quantity - required
42
+ # )
43
+ #
44
+ # # submit the transaction
45
+ # analytics_track_transaction
46
+ #
47
+ module ViewHelpers
48
+ # Initializes the Analytics javascript. Put it in the `<head>` tag.
49
+ #
50
+ # @param options [Hash]
51
+ # @option options [String] :name
52
+ # The name of the Universal Analytics Tracker
53
+ # @option options [Hash] :setup
54
+ # Options for the initial Setup {GoogleAnalytics::Events::SetupAnalytics}
55
+ # @option options [Boolean] :local (false) Sets the local development mode.
56
+ # See {http://www.google.com/support/forum/p/Google%20Analytics/thread?tid=741739888e14c07a&hl=en}
57
+ # @option options [Array, GoogleAnalytics::Event] :add_events ([])
58
+ # The page views are tracked by default, additional events can be added here.
59
+ # @option options [Boolean] :skip_pageview
60
+ # Turn off pageview tracking
61
+ # @option options [String] :page
62
+ # The optional virtual page view to track through {GoogleAnalytics::Events::TrackPageview}
63
+ # @option options [String] :title
64
+ # The optional virtual page view to track through {GoogleAnalytics::Events::TrackPageview}
65
+ # @option options [String] :tracker
66
+ # The tracker to use instead of the default {GoogleAnalytics.tracker}
67
+ # @option options [String] :domain
68
+ # The domain name to track, see {GoogleAnalytics::Events::SetDomainName}
69
+ # @option options [Boolean] :anonymize
70
+ # Whether to anonymize the visitor ip or not.
71
+ # This is required for european websites and actively enforced for german ones,
72
+ # see {GoogleAnalytics::Events::AnonymizeIp}.
73
+ # @option options [Boolean] :enhanced_link_attribution
74
+ # See separate information for multiple links on a page that all have the same destination,
75
+ # see {https://support.google.com/analytics/answer/2558867}.
76
+ # @option options [Array, GoogleAnalytics::Events::SetCustomDimension, GoogleAnalytics::Events::SetCustomMetric] :custom_vars ([])
77
+ #
78
+ # @example Set the local bit in development mode
79
+ # analytics_init :local => Rails.env.development?
80
+ #
81
+ # @example Allow links across domains
82
+ # analytics_init :add_events => Events::SetAllowLinker.new(true)
83
+ #
84
+ # @return [String] a `<script>` tag, containing the analytics initialization sequence.
85
+ #
86
+ def analytics_init(options = {})
87
+ unless tracker = options.delete(:tracker).presence
88
+ tracker = GA.tracker
89
+ raise ArgumentError, "Tracker must be set! Did you set GA.tracker ?" unless tracker
90
+ end
91
+
92
+ local = options.delete(:local) || false
93
+ setup = options.delete(:setup) || {}
94
+ tracker_name = options.delete(:name) || setup.fetch(:name, nil)
95
+
96
+ # Determine Name
97
+ setup[:name] ||= tracker_name if tracker_name
98
+
99
+ domain = options.delete(:domain) || (local ? "none" : "auto")
100
+
101
+ skip_pageview = options.delete(:skip_pageview) || false
102
+ anonymize = options.delete(:anonymize) || false
103
+ custom_vars = options.delete(:custom_vars) || []
104
+ custom_vars = [custom_vars] unless custom_vars.is_a?(Array)
105
+
106
+ link_attribution = options.delete(:enhanced_link_attribution) || false
107
+
108
+
109
+ events = options.delete(:add_events) || []
110
+ events = [events] unless events.is_a?(Array)
111
+
112
+ # Convert older classes when we can
113
+ if events.any?{|x| x.class.name == 'GoogleAnalytics::Events::SetAllowLinker' }
114
+ setup[:allowLinker] = !!events.any?{|x| x.class.name == 'GoogleAnalytics::Events::SetAllowLinker' }
115
+ events.delete_if{|x| x.class.name == 'GoogleAnalytics::Events::SetAllowLinker' }
116
+ end
117
+
118
+ if events.any?{|x| x.class.name == 'GoogleAnalytics::Events::SetSiteSpeedSampleRate' }
119
+ setup[:siteSpeedSampleRate] = events.select{|x| x.class.name == 'GoogleAnalytics::Events::SetSiteSpeedSampleRate' }.first.sample_rate
120
+ events.delete_if{|x| x.class.name == 'GoogleAnalytics::Events::SetSiteSpeedSampleRate' }
121
+ end
122
+
123
+ queue = GAQ.new
124
+ # unshift => reverse order
125
+ events.unshift GA::Events::TrackPageview.new({:page => options[:page], :title => options[:title]}) unless skip_pageview
126
+ # anonymize if needed before tracking the page view
127
+ events.unshift GA::Events::AnonymizeIp.new if anonymize
128
+ # custom_var if needed before tracking the page view
129
+ custom_vars.each do |custom_var|
130
+ events.unshift custom_var
131
+ end
132
+
133
+ events.unshift GA::Events::Require.new('linkid') if link_attribution
134
+
135
+ # If this is 'local' env, give the cookieDomain none, and allow linker
136
+ if local
137
+ events.unshift GA::Events::SetupAnalytics.new(tracker, setup.merge({
138
+ :cookieDomain => 'none',
139
+ :allowLinker => true
140
+ }))
141
+ # If we have any configs, we'll merge the cookieDomain in
142
+ elsif setup.any?
143
+ events.unshift GA::Events::SetupAnalytics.new(tracker, setup.merge({ :cookieDomain => domain }))
144
+ # Just a normal request
145
+ else
146
+ events.unshift GA::Events::SetupAnalytics.new(tracker, domain)
147
+ end
148
+
149
+ events.each do |evt|
150
+ if evt.class.name == 'GoogleAnalytics::Events::SetupAnalytics'
151
+ queue.push(evt)
152
+ else
153
+ queue.push(evt, tracker_name)
154
+ end
155
+ end
156
+
157
+ queue.to_s.html_safe
158
+ end
159
+
160
+ # Track a custom event
161
+ # @see http://code.google.com/apis/analytics/docs/tracking/eventTrackerGuide.html
162
+ #
163
+ # @example
164
+ #
165
+ # analytics_track_event "Videos", "Play", "Gone With the Wind"
166
+ #
167
+ def analytics_track_event(category, action, label = nil, value = nil)
168
+ analytics_render_event(GA::Events::TrackEvent.new(category, action, label, value))
169
+ end
170
+
171
+ # Set a custom variable.
172
+ # @see http://code.google.com/apis/analytics/docs/tracking/gaTrackingCustomVariables.html
173
+ # You're allowed only 1-5 for the index.
174
+ # The lifetime is defined by:
175
+ # 1 = visitor-level
176
+ # 2 = session-level
177
+ # 3 = page-level (default)
178
+ def analytics_set_custom_var(index, name, value, opt_scope = 3)
179
+ analytics_render_event(GA::Events::SetCustomVar.new(index, name, value, opt_scope))
180
+ end
181
+
182
+ # Track an ecommerce transaction
183
+ # @see http://code.google.com/apis/analytics/docs/tracking/gaTrackingEcommerce.html
184
+ def analytics_add_transaction(order_id, store_name, total, tax, shipping, city, state_or_province, country)
185
+ analytics_render_event(GA::Events::Require.new('ecommerce','ecommerce.js'))
186
+ analytics_render_event(GA::Events::Ecommerce::AddTransaction.new(order_id, store_name, total, tax, shipping, city, state_or_province, country))
187
+ end
188
+
189
+ # Add an item to the current transaction
190
+ # @see http://code.google.com/apis/analytics/docs/tracking/gaTrackingEcommerce.html
191
+ def analytics_add_item(order_id, product_id, product_name, product_variation, unit_price, quantity)
192
+ analytics_render_event(GA::Events::Ecommerce::AddItem.new(order_id, product_id, product_name, product_variation, unit_price, quantity))
193
+ end
194
+
195
+ # Flush the current transaction
196
+ # @see http://code.google.com/apis/analytics/docs/tracking/gaTrackingEcommerce.html
197
+ def analytics_track_transaction
198
+ analytics_render_event(GA::Events::Ecommerce::TrackTransaction.new)
199
+ end
200
+
201
+ private
202
+
203
+ def analytics_render_event(event)
204
+ raise ArgumentError, "Tracker must be set! Did you set GA.tracker ?" unless GA.valid_tracker?
205
+ GA::EventRenderer.new(event, nil).to_s.html_safe
206
+ end
207
+ end
208
+ end