ahoy_matey 0.1.8 → 0.2.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 +5 -0
- data/README.md +151 -49
- data/app/controllers/ahoy/events_controller.rb +14 -0
- data/app/controllers/ahoy/visits_controller.rb +1 -1
- data/app/models/ahoy/event.rb +10 -0
- data/config/routes.rb +1 -0
- data/lib/ahoy/controller.rb +5 -0
- data/lib/ahoy/subscribers/active_record.rb +21 -0
- data/lib/ahoy/tracker.rb +30 -0
- data/lib/ahoy/version.rb +1 -1
- data/lib/ahoy_matey.rb +4 -0
- data/lib/generators/ahoy/events/active_record_generator.rb +36 -0
- data/lib/generators/ahoy/events/templates/create_events.rb +20 -0
- data/lib/generators/ahoy/events/templates/initializer.rb +1 -0
- data/vendor/assets/javascripts/ahoy.js +145 -22
- metadata +9 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c1ddf7a214c83d60f35b1d7a39653ef65d5ab3ee
|
4
|
+
data.tar.gz: e3c9af288c825faffda2cb7bf97cd8aa248c41a6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e3c068287e17bc73b51ce57af242a91013720b64dceefb00330a85ac2c586ba9b11b3fdd6395b9d8adf3d952b9dee1a73557d16a6a8792a49fa62d9c1893ba3c
|
7
|
+
data.tar.gz: 137594a001bb62a37274b94fe7776074b0880e74ddfdd0d48cc305d67847d13ca056de3f6fe38161d180d13cf22f79d6d363888a949d2d3abbdea8eed056d7cd
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Ahoy
|
2
2
|
|
3
|
-
:fire: Simple, powerful
|
3
|
+
:fire: Simple, powerful analytics for Rails
|
4
4
|
|
5
5
|
Visits are stored in **your database** so you can easily combine them with other data.
|
6
6
|
|
@@ -11,16 +11,18 @@ You get:
|
|
11
11
|
- **technology** - browser, OS, and device type
|
12
12
|
- **utm parameters** - source, medium, term, content, campaign
|
13
13
|
|
14
|
-
|
14
|
+
Track events in:
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
16
|
+
- JavaScript
|
17
|
+
- Ruby
|
18
|
+
- Native apps
|
19
19
|
|
20
|
-
|
20
|
+
And store them wherever you’d like - your database, logs, external services, or all of them.
|
21
21
|
|
22
22
|
:postbox: To track emails, check out [Ahoy Email](https://github.com/ankane/ahoy_email).
|
23
23
|
|
24
|
+
No Ruby? Check out [Ahoy.js](https://github.com/ankane/ahoy.js).
|
25
|
+
|
24
26
|
## Installation
|
25
27
|
|
26
28
|
Add this line to your application’s Gemfile:
|
@@ -93,8 +95,6 @@ Order.joins(:visit).group("device_type").count
|
|
93
95
|
|
94
96
|
Ahoy automatically attaches the `current_user` to the `current_visit`.
|
95
97
|
|
96
|
-
If you define your own `current_user` method, be sure to add it to `ActionController::Base`, not `ApplicationController`.
|
97
|
-
|
98
98
|
With [Devise](https://github.com/plataformatec/devise), it will attach the user even if he / she signs in after the visit starts.
|
99
99
|
|
100
100
|
With other authentication frameworks, add this to the end of your sign in method:
|
@@ -135,19 +135,104 @@ or
|
|
135
135
|
http://datakick.org/?utm_medium=twitter&utm_campaign=social&utm_source=tweet123
|
136
136
|
```
|
137
137
|
|
138
|
-
###
|
138
|
+
### Native Apps
|
139
139
|
|
140
|
-
|
140
|
+
When a user launches the app, create a visit. Send a `POST` request to `/ahoy/visits` with:
|
141
141
|
|
142
|
-
|
142
|
+
- platform - `iOS`, `Android`, etc.
|
143
|
+
- app_version - `1.0.0`
|
144
|
+
- os_version - `7.0.6`
|
145
|
+
- visitor_token - if you have one
|
143
146
|
|
144
|
-
|
147
|
+
The endpoint will return a JSON response like:
|
148
|
+
|
149
|
+
```json
|
150
|
+
{
|
151
|
+
"visit_token": "8tx2ziymkwa1WlppnkqxyaBaRlXrEQ3K",
|
152
|
+
"visitor_token": "hYBIV0rBfrIUAiArWweiECt4N9pyiygN"
|
153
|
+
}
|
154
|
+
```
|
155
|
+
|
156
|
+
Send the visit token in the `Ahoy-Visit` header for all requests.
|
157
|
+
|
158
|
+
After 4 hours, create another visit and use the updated visit token.
|
159
|
+
|
160
|
+
## Events
|
161
|
+
|
162
|
+
Each event has a `name` and `properties`.
|
163
|
+
|
164
|
+
There are three ways to track events.
|
165
|
+
|
166
|
+
#### JavaScript
|
145
167
|
|
146
168
|
```javascript
|
147
|
-
|
169
|
+
ahoy.track("Viewed book", {title: "The World is Flat"});
|
170
|
+
```
|
171
|
+
|
172
|
+
or track all views and clicks with:
|
173
|
+
|
174
|
+
```javascript
|
175
|
+
ahoy.trackAll();
|
176
|
+
```
|
177
|
+
|
178
|
+
#### Ruby
|
179
|
+
|
180
|
+
```ruby
|
181
|
+
ahoy.track "Viewed book", title: "Hot, Flat, and Crowded"
|
148
182
|
```
|
149
183
|
|
150
|
-
|
184
|
+
#### Native Apps
|
185
|
+
|
186
|
+
Send a `POST` request to `/ahoy/events` with:
|
187
|
+
|
188
|
+
- name
|
189
|
+
- properties
|
190
|
+
- user token (depends on your authentication framework)
|
191
|
+
- `Ahoy-Visit` header
|
192
|
+
|
193
|
+
Requests should have `Content-Type: application/json`.
|
194
|
+
|
195
|
+
### Storing Events
|
196
|
+
|
197
|
+
You choose how to store events.
|
198
|
+
|
199
|
+
#### ActiveRecord
|
200
|
+
|
201
|
+
Create an `Ahoy::Event` model to store events.
|
202
|
+
|
203
|
+
```sh
|
204
|
+
rails generate ahoy:events:active_record
|
205
|
+
rake db:migrate
|
206
|
+
```
|
207
|
+
|
208
|
+
#### Custom
|
209
|
+
|
210
|
+
Create your own subscribers in `config/initializers/ahoy.rb`.
|
211
|
+
|
212
|
+
```ruby
|
213
|
+
class LogSubscriber
|
214
|
+
|
215
|
+
def track(name, properties, options = {})
|
216
|
+
data = {
|
217
|
+
name: name,
|
218
|
+
properties: properties,
|
219
|
+
time: options[:time].to_i,
|
220
|
+
visit_id: options[:visit].try(:id),
|
221
|
+
user_id: options[:user].try(:id),
|
222
|
+
ip: options[:controller].try(:request).try(:remote_ip)
|
223
|
+
}
|
224
|
+
Rails.logger.info data.to_json
|
225
|
+
end
|
226
|
+
|
227
|
+
end
|
228
|
+
|
229
|
+
# and add it
|
230
|
+
Ahoy.subscribers << LogSubscriber.new
|
231
|
+
```
|
232
|
+
|
233
|
+
Add as many subscribers as you’d like.
|
234
|
+
|
235
|
+
## Development
|
151
236
|
|
152
237
|
Ahoy is built with developers in mind. You can run the following code in your browser’s console.
|
153
238
|
|
@@ -169,27 +254,12 @@ Turn off logging
|
|
169
254
|
ahoy.debug(false);
|
170
255
|
```
|
171
256
|
|
172
|
-
###
|
173
|
-
|
174
|
-
When a user launches the app, create a visit. Send a `POST` request to `/ahoy/visits` with:
|
175
|
-
|
176
|
-
- platform - `iOS`, `Android`, etc.
|
177
|
-
- app_version - `1.0.0`
|
178
|
-
- os_version - `7.0.6`
|
179
|
-
- visitor_token - if you have one
|
180
|
-
|
181
|
-
The endpoint will return a JSON response like:
|
182
|
-
|
183
|
-
```json
|
184
|
-
{
|
185
|
-
"visit_token": "8tx2ziymkwa1WlppnkqxyaBaRlXrEQ3K",
|
186
|
-
"visitor_token": "hYBIV0rBfrIUAiArWweiECt4N9pyiygN"
|
187
|
-
}
|
188
|
-
```
|
189
|
-
|
190
|
-
Send the visit token in the `Ahoy-Visit` header for all requests.
|
257
|
+
### More
|
191
258
|
|
192
|
-
|
259
|
+
- Excludes bots
|
260
|
+
- Degrades gracefully when cookies are disabled
|
261
|
+
- Don’t need a field? Just remove it from the migration
|
262
|
+
- Visits are 4 hours by default
|
193
263
|
|
194
264
|
### Doorkeeper
|
195
265
|
|
@@ -207,24 +277,12 @@ class ApplicationController < ActionController::Base
|
|
207
277
|
end
|
208
278
|
```
|
209
279
|
|
210
|
-
### More
|
211
|
-
|
212
|
-
- Excludes bots
|
213
|
-
- Degrades gracefully when cookies are disabled
|
214
|
-
- Don’t need a field? Just remove it from the migration
|
215
|
-
- Visits are 4 hours by default
|
216
|
-
|
217
280
|
## Reference
|
218
281
|
|
219
|
-
|
220
|
-
|
221
|
-
```ruby
|
222
|
-
Ahoy.visit_model = UserVisit
|
282
|
+
To track visits across multiple subdomains, add this **before** the javascript files.
|
223
283
|
|
224
|
-
|
225
|
-
|
226
|
-
Ahoy.visit_model = UserVisit
|
227
|
-
end
|
284
|
+
```javascript
|
285
|
+
var ahoy = {"domain": "yourdomain.com"};
|
228
286
|
```
|
229
287
|
|
230
288
|
Change the platform on the web
|
@@ -266,6 +324,49 @@ Customize visitable
|
|
266
324
|
visitable :sign_up_visit, class_name: "Visit"
|
267
325
|
```
|
268
326
|
|
327
|
+
Track view
|
328
|
+
|
329
|
+
```javascript
|
330
|
+
ahoy.trackView();
|
331
|
+
```
|
332
|
+
|
333
|
+
Track clicks
|
334
|
+
|
335
|
+
```javascript
|
336
|
+
ahoy.trackClicks();
|
337
|
+
```
|
338
|
+
|
339
|
+
Track all Rails actions
|
340
|
+
|
341
|
+
```ruby
|
342
|
+
class ApplicationController < ActionController::Base
|
343
|
+
after_filter :track_action
|
344
|
+
|
345
|
+
protected
|
346
|
+
|
347
|
+
def track_action
|
348
|
+
ahoy.track "Hit action", request.filtered_parameters
|
349
|
+
end
|
350
|
+
end
|
351
|
+
```
|
352
|
+
|
353
|
+
Use a different model for visits
|
354
|
+
|
355
|
+
```ruby
|
356
|
+
Ahoy.visit_model = UserVisit
|
357
|
+
|
358
|
+
# fix for Rails reloader in development
|
359
|
+
ActionDispatch::Reloader.to_prepare do
|
360
|
+
Ahoy.visit_model = UserVisit
|
361
|
+
end
|
362
|
+
```
|
363
|
+
|
364
|
+
Use a different model for events
|
365
|
+
|
366
|
+
```ruby
|
367
|
+
Ahoy.subscribers << Ahoy::Subscribers::ActiveRecord.new(model: Event)
|
368
|
+
```
|
369
|
+
|
269
370
|
## Upgrading
|
270
371
|
|
271
372
|
In `0.1.6`, a big improvement was made to `browser` and `os`. Update existing visits with:
|
@@ -279,6 +380,7 @@ end
|
|
279
380
|
|
280
381
|
## TODO
|
281
382
|
|
383
|
+
- better readme
|
282
384
|
- simple dashboard
|
283
385
|
- turn off modules
|
284
386
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Ahoy
|
2
|
+
class EventsController < Ahoy::BaseController
|
3
|
+
|
4
|
+
def create
|
5
|
+
options = {}
|
6
|
+
if params[:time] and (time = Time.at(params[:time].to_f) rescue nil) and (1.minute.ago..Time.now).cover?(time)
|
7
|
+
options[:time] = time
|
8
|
+
end
|
9
|
+
ahoy.track params[:name], params[:properties], options
|
10
|
+
render json: {}
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
data/config/routes.rb
CHANGED
data/lib/ahoy/controller.rb
CHANGED
@@ -3,6 +3,7 @@ module Ahoy
|
|
3
3
|
|
4
4
|
def self.included(base)
|
5
5
|
base.helper_method :current_visit
|
6
|
+
base.helper_method :ahoy
|
6
7
|
base.before_filter do
|
7
8
|
RequestStore.store[:ahoy_controller] ||= self
|
8
9
|
end
|
@@ -15,5 +16,9 @@ module Ahoy
|
|
15
16
|
end
|
16
17
|
end
|
17
18
|
|
19
|
+
def ahoy
|
20
|
+
@ahoy ||= Ahoy::Tracker.new(controller: self)
|
21
|
+
end
|
22
|
+
|
18
23
|
end
|
19
24
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Ahoy
|
2
|
+
module Subscribers
|
3
|
+
class ActiveRecord
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
@model = options[:model] || Ahoy::Event
|
7
|
+
end
|
8
|
+
|
9
|
+
def track(name, properties, options = {})
|
10
|
+
@model.create! do |e|
|
11
|
+
e.visit = options[:visit]
|
12
|
+
e.user = options[:user]
|
13
|
+
e.name = name
|
14
|
+
e.properties = properties
|
15
|
+
e.time = options[:time]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/ahoy/tracker.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
module Ahoy
|
2
|
+
class Tracker
|
3
|
+
|
4
|
+
def initialize(options = {})
|
5
|
+
@controller = options[:controller]
|
6
|
+
end
|
7
|
+
|
8
|
+
def track(name, properties, options = {})
|
9
|
+
# publish to each subscriber
|
10
|
+
if @controller
|
11
|
+
options[:controller] ||= @controller
|
12
|
+
options[:user] ||= Ahoy.fetch_user(@controller)
|
13
|
+
if @controller.respond_to?(:current_visit)
|
14
|
+
options[:visit] ||= @controller.current_visit
|
15
|
+
end
|
16
|
+
end
|
17
|
+
options[:time] ||= Time.zone.now
|
18
|
+
|
19
|
+
subscribers = Ahoy.subscribers
|
20
|
+
if subscribers.any?
|
21
|
+
subscribers.each do |subscriber|
|
22
|
+
subscriber.track(name, properties, options)
|
23
|
+
end
|
24
|
+
else
|
25
|
+
$stderr.puts "No subscribers"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
data/lib/ahoy/version.rb
CHANGED
data/lib/ahoy_matey.rb
CHANGED
@@ -5,8 +5,10 @@ require "referer-parser"
|
|
5
5
|
require "user_agent_parser"
|
6
6
|
require "request_store"
|
7
7
|
require "ahoy/version"
|
8
|
+
require "ahoy/tracker"
|
8
9
|
require "ahoy/controller"
|
9
10
|
require "ahoy/model"
|
11
|
+
require "ahoy/subscribers/active_record"
|
10
12
|
require "ahoy/engine"
|
11
13
|
|
12
14
|
module Ahoy
|
@@ -43,6 +45,8 @@ module Ahoy
|
|
43
45
|
(controller.respond_to?(:current_user) && controller.current_user) || (controller.respond_to?(:current_resource_owner, true) && controller.send(:current_resource_owner)) || nil
|
44
46
|
end
|
45
47
|
|
48
|
+
mattr_accessor :subscribers
|
49
|
+
self.subscribers = []
|
46
50
|
end
|
47
51
|
|
48
52
|
ActionController::Base.send :include, Ahoy::Controller
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# taken from https://github.com/collectiveidea/audited/blob/master/lib/generators/audited/install_generator.rb
|
2
|
+
require "rails/generators"
|
3
|
+
require "rails/generators/migration"
|
4
|
+
require "active_record"
|
5
|
+
require "rails/generators/active_record"
|
6
|
+
|
7
|
+
module Ahoy
|
8
|
+
module Events
|
9
|
+
module Generators
|
10
|
+
class ActiveRecordGenerator < Rails::Generators::Base
|
11
|
+
include Rails::Generators::Migration
|
12
|
+
|
13
|
+
source_root File.expand_path("../templates", __FILE__)
|
14
|
+
|
15
|
+
# Implement the required interface for Rails::Generators::Migration.
|
16
|
+
def self.next_migration_number(dirname) #:nodoc:
|
17
|
+
next_migration_number = current_migration_number(dirname) + 1
|
18
|
+
if ActiveRecord::Base.timestamped_migrations
|
19
|
+
[Time.now.utc.strftime("%Y%m%d%H%M%S"), "%.14d" % next_migration_number].max
|
20
|
+
else
|
21
|
+
"%.3d" % next_migration_number
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def copy_migration
|
26
|
+
migration_template "create_events.rb", "db/migrate/create_ahoy_events.rb"
|
27
|
+
end
|
28
|
+
|
29
|
+
def create_initializer
|
30
|
+
template "initializer.rb", "config/initializers/ahoy.rb"
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class <%= migration_class_name %> < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :ahoy_events do |t|
|
4
|
+
# visit
|
5
|
+
t.references :visit
|
6
|
+
|
7
|
+
# user
|
8
|
+
t.integer :user_id
|
9
|
+
t.string :user_type
|
10
|
+
|
11
|
+
t.string :name
|
12
|
+
t.text :properties
|
13
|
+
t.timestamp :time
|
14
|
+
end
|
15
|
+
|
16
|
+
add_index :ahoy_events, [:visit_id]
|
17
|
+
add_index :ahoy_events, [:user_id, :user_type]
|
18
|
+
add_index :ahoy_events, [:time]
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Ahoy.subscribers << Ahoy::Subscribers::ActiveRecord.new
|
@@ -10,6 +10,8 @@
|
|
10
10
|
var visitorTtl = 2 * 365 * 24 * 60; // 2 years
|
11
11
|
var isReady = false;
|
12
12
|
var queue = [];
|
13
|
+
var canStringify = typeof(JSON) !== "undefined" && typeof(JSON.stringify) !== "undefined";
|
14
|
+
var eventQueue = [];
|
13
15
|
|
14
16
|
// cookies
|
15
17
|
|
@@ -62,25 +64,98 @@
|
|
62
64
|
isReady = true;
|
63
65
|
}
|
64
66
|
|
67
|
+
function ready(callback) {
|
68
|
+
if (isReady) {
|
69
|
+
callback();
|
70
|
+
} else {
|
71
|
+
queue.push(callback);
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
// https://github.com/klughammer/node-randomstring
|
76
|
+
function generateId() {
|
77
|
+
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghiklmnopqrstuvwxyz';
|
78
|
+
var length = 32;
|
79
|
+
var string = '';
|
80
|
+
|
81
|
+
for (var i = 0; i < length; i++) {
|
82
|
+
var randomNumber = Math.floor(Math.random() * chars.length);
|
83
|
+
string += chars.substring(randomNumber, randomNumber + 1);
|
84
|
+
}
|
85
|
+
|
86
|
+
return string;
|
87
|
+
}
|
88
|
+
|
89
|
+
function saveEventQueue() {
|
90
|
+
// TODO add stringify method for IE 7 and under
|
91
|
+
if (canStringify) {
|
92
|
+
setCookie("ahoy_events", JSON.stringify(eventQueue), 1);
|
93
|
+
}
|
94
|
+
}
|
95
|
+
|
96
|
+
function trackEvent(event) {
|
97
|
+
ready( function () {
|
98
|
+
// ensure JSON is defined
|
99
|
+
if (canStringify) {
|
100
|
+
$.ajax({
|
101
|
+
type: "POST",
|
102
|
+
url: "/ahoy/events",
|
103
|
+
data: JSON.stringify(event),
|
104
|
+
contentType: "application/json; charset=utf-8",
|
105
|
+
dataType: "json",
|
106
|
+
success: function() {
|
107
|
+
// remove from queue
|
108
|
+
for (var i = 0; i < eventQueue.length; i++) {
|
109
|
+
if (eventQueue[i].id == event.id) {
|
110
|
+
eventQueue.splice(i, 1);
|
111
|
+
break;
|
112
|
+
}
|
113
|
+
}
|
114
|
+
saveEventQueue();
|
115
|
+
}
|
116
|
+
});
|
117
|
+
}
|
118
|
+
});
|
119
|
+
}
|
120
|
+
|
121
|
+
function eventProperties(e) {
|
122
|
+
var $target = $(e.currentTarget);
|
123
|
+
return {
|
124
|
+
tag: $target.get(0).tagName.toLowerCase(),
|
125
|
+
id: $target.attr("id"),
|
126
|
+
class: $target.attr("class")
|
127
|
+
};
|
128
|
+
}
|
129
|
+
|
65
130
|
// main
|
66
131
|
|
67
132
|
visitToken = getCookie("ahoy_visit");
|
68
133
|
visitorToken = getCookie("ahoy_visitor");
|
69
134
|
|
70
|
-
if (visitToken && visitorToken
|
135
|
+
if (visitToken && visitorToken) {
|
71
136
|
// TODO keep visit alive?
|
72
137
|
log("Active visit");
|
73
138
|
setReady();
|
74
139
|
} else {
|
75
|
-
|
140
|
+
visitToken = generateId();
|
141
|
+
setCookie("ahoy_visit", visitToken, visitTtl);
|
76
142
|
|
77
143
|
// make sure cookies are enabled
|
78
144
|
if (getCookie("ahoy_visit")) {
|
79
145
|
log("Visit started");
|
80
146
|
|
147
|
+
if (!visitorToken) {
|
148
|
+
visitorToken = generateId();
|
149
|
+
setCookie("ahoy_visitor", visitorToken, visitorTtl);
|
150
|
+
}
|
151
|
+
|
81
152
|
var data = {
|
153
|
+
visit_token: visitToken,
|
154
|
+
visitor_token: visitorToken,
|
82
155
|
platform: ahoy.platform || "Web",
|
83
|
-
landing_page: window.location.href
|
156
|
+
landing_page: window.location.href,
|
157
|
+
screen_width: window.screen.width,
|
158
|
+
screen_height: window.screen.height
|
84
159
|
};
|
85
160
|
|
86
161
|
// referrer
|
@@ -88,17 +163,9 @@
|
|
88
163
|
data.referrer = document.referrer;
|
89
164
|
}
|
90
165
|
|
91
|
-
if (visitorToken) {
|
92
|
-
data.visitor_token = visitorToken;
|
93
|
-
}
|
94
|
-
|
95
166
|
log(data);
|
96
167
|
|
97
|
-
$.post("/ahoy/visits", data,
|
98
|
-
setCookie("ahoy_visit", response.visit_token, visitTtl);
|
99
|
-
setCookie("ahoy_visitor", response.visitor_token, visitorTtl);
|
100
|
-
setReady();
|
101
|
-
}, "json");
|
168
|
+
$.post("/ahoy/visits", data, setReady, "json");
|
102
169
|
} else {
|
103
170
|
log("Cookies disabled");
|
104
171
|
setReady();
|
@@ -120,18 +187,74 @@
|
|
120
187
|
return true;
|
121
188
|
};
|
122
189
|
|
123
|
-
ahoy.
|
124
|
-
|
125
|
-
|
126
|
-
|
190
|
+
ahoy.track = function (name, properties) {
|
191
|
+
// generate unique id
|
192
|
+
var event = {
|
193
|
+
id: generateId(),
|
194
|
+
name: name,
|
195
|
+
properties: properties,
|
196
|
+
time: (new Date()).getTime() / 1000.0
|
197
|
+
};
|
198
|
+
log(event);
|
127
199
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
200
|
+
eventQueue.push(event);
|
201
|
+
saveEventQueue();
|
202
|
+
|
203
|
+
// wait in case navigating to reduce duplicate events
|
204
|
+
setTimeout( function () {
|
205
|
+
trackEvent(event);
|
206
|
+
}, 1000);
|
207
|
+
};
|
208
|
+
|
209
|
+
ahoy.trackView = function () {
|
210
|
+
var properties = {
|
211
|
+
url: window.location.href,
|
212
|
+
title: document.title
|
213
|
+
};
|
214
|
+
ahoy.track("$view", properties);
|
215
|
+
};
|
216
|
+
|
217
|
+
ahoy.trackClicks = function () {
|
218
|
+
$(document).on("click", "a, button, input[type=submit]", function (e) {
|
219
|
+
var $target = $(e.currentTarget);
|
220
|
+
var properties = eventProperties(e);
|
221
|
+
properties.text = properties.tag == "input" ? $target.val() : $.trim($target.text());
|
222
|
+
properties.href = $target.attr("href");
|
223
|
+
ahoy.track("$click", properties);
|
224
|
+
});
|
225
|
+
};
|
226
|
+
|
227
|
+
ahoy.trackSubmits = function () {
|
228
|
+
$(document).on("submit", "form", function (e) {
|
229
|
+
var properties = eventProperties(e);
|
230
|
+
ahoy.track("$submit", properties);
|
231
|
+
});
|
134
232
|
};
|
135
233
|
|
234
|
+
ahoy.trackChanges = function () {
|
235
|
+
$(document).on("change", "input, textarea, select", function (e) {
|
236
|
+
var properties = eventProperties(e);
|
237
|
+
ahoy.track("$change", properties);
|
238
|
+
});
|
239
|
+
};
|
240
|
+
|
241
|
+
ahoy.trackAll = function() {
|
242
|
+
ahoy.trackView();
|
243
|
+
ahoy.trackClicks();
|
244
|
+
ahoy.trackSubmits();
|
245
|
+
ahoy.trackChanges();
|
246
|
+
};
|
247
|
+
|
248
|
+
// push events from queue
|
249
|
+
try {
|
250
|
+
eventQueue = JSON.parse(getCookie("ahoy_events") || "[]");
|
251
|
+
} catch (e) {
|
252
|
+
// do nothing
|
253
|
+
}
|
254
|
+
|
255
|
+
for (var i = 0; i < eventQueue.length; i++) {
|
256
|
+
trackEvent(eventQueue[i]);
|
257
|
+
}
|
258
|
+
|
136
259
|
window.ahoy = ahoy;
|
137
260
|
}(window));
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ahoy_matey
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-05-
|
11
|
+
date: 2014-05-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -137,13 +137,20 @@ files:
|
|
137
137
|
- Rakefile
|
138
138
|
- ahoy_matey.gemspec
|
139
139
|
- app/controllers/ahoy/base_controller.rb
|
140
|
+
- app/controllers/ahoy/events_controller.rb
|
140
141
|
- app/controllers/ahoy/visits_controller.rb
|
142
|
+
- app/models/ahoy/event.rb
|
141
143
|
- config/routes.rb
|
142
144
|
- lib/ahoy/controller.rb
|
143
145
|
- lib/ahoy/engine.rb
|
144
146
|
- lib/ahoy/model.rb
|
147
|
+
- lib/ahoy/subscribers/active_record.rb
|
148
|
+
- lib/ahoy/tracker.rb
|
145
149
|
- lib/ahoy/version.rb
|
146
150
|
- lib/ahoy_matey.rb
|
151
|
+
- lib/generators/ahoy/events/active_record_generator.rb
|
152
|
+
- lib/generators/ahoy/events/templates/create_events.rb
|
153
|
+
- lib/generators/ahoy/events/templates/initializer.rb
|
147
154
|
- lib/generators/ahoy/install_generator.rb
|
148
155
|
- lib/generators/ahoy/templates/install.rb
|
149
156
|
- vendor/assets/javascripts/ahoy.js
|