ahoy_matey 0.1.8 → 0.2.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
  SHA1:
3
- metadata.gz: e26a906ddc293ac0416f2f254d784cfc6db73003
4
- data.tar.gz: 541082bbd91a7633e0dbec197f8107e5d4eda36b
3
+ metadata.gz: c1ddf7a214c83d60f35b1d7a39653ef65d5ab3ee
4
+ data.tar.gz: e3c9af288c825faffda2cb7bf97cd8aa248c41a6
5
5
  SHA512:
6
- metadata.gz: 003f1ce5a22f8a075dc29e2f1fec577621977152821cfd4bff6f8f6b930237909f9b63ca148efc03d9ddc12f8224a1f60f6683f1753ba801569ca745dab03898
7
- data.tar.gz: bdc8fe84047e09ffec04fa4464c30698ef7be5771749a2fce969e70b704676e33395ff2cb508e9541c3930111228fa5d3b17e46b01b661fb791ea686b18a320a
6
+ metadata.gz: e3c068287e17bc73b51ce57af242a91013720b64dceefb00330a85ac2c586ba9b11b3fdd6395b9d8adf3d952b9dee1a73557d16a6a8792a49fa62d9c1893ba3c
7
+ data.tar.gz: 137594a001bb62a37274b94fe7776074b0880e74ddfdd0d48cc305d67847d13ca056de3f6fe38161d180d13cf22f79d6d363888a949d2d3abbdea8eed056d7cd
@@ -1,3 +1,8 @@
1
+ ## 0.2.0
2
+
3
+ - Added event tracking (merged ahoy_events)
4
+ - Added ahoy.js
5
+
1
6
  ## 0.1.8
2
7
 
3
8
  - Fixed bug with `user_type` set to `false` instead of `nil`
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Ahoy
2
2
 
3
- :fire: Simple, powerful visit tracking for Rails
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
- See which campaigns generate the most revenue effortlessly.
14
+ Track events in:
15
15
 
16
- ```ruby
17
- Order.joins(:visit).group("utm_campaign").sum(:revenue)
18
- ```
16
+ - JavaScript
17
+ - Ruby
18
+ - Native apps
19
19
 
20
- :seedling: To track events like page views, check out [Ahoy Events](https://github.com/ankane/ahoy_events).
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
- ### Location
138
+ ### Native Apps
139
139
 
140
- Ahoy uses [Geocoder](https://github.com/alexreisner/geocoder) for IP-based geocoding.
140
+ When a user launches the app, create a visit. Send a `POST` request to `/ahoy/visits` with:
141
141
 
142
- ### Multiple Subdomains
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
- To track visits across multiple subdomains, add this **before** the javascript files.
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
- var ahoy = {"domain": "yourdomain.com"};
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
- ### Development
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
- ### Native Apps
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
- After 4 hours, create another visit and use the updated visit token.
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
- Use a different model
220
-
221
- ```ruby
222
- Ahoy.visit_model = UserVisit
282
+ To track visits across multiple subdomains, add this **before** the javascript files.
223
283
 
224
- # fix for Rails reloader in development
225
- ActionDispatch::Reloader.to_prepare do
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
@@ -2,7 +2,7 @@ module Ahoy
2
2
  class VisitsController < BaseController
3
3
 
4
4
  def create
5
- visit_token = generate_token
5
+ visit_token = params[:visit_token] || generate_token
6
6
  visitor_token = params[:visitor_token] || generate_token
7
7
 
8
8
  visit =
@@ -0,0 +1,10 @@
1
+ module Ahoy
2
+ class Event < ActiveRecord::Base
3
+ self.table_name = "ahoy_events"
4
+
5
+ belongs_to :visit
6
+ belongs_to :user, polymorphic: true
7
+
8
+ serialize :properties, JSON
9
+ end
10
+ end
@@ -5,5 +5,6 @@ end
5
5
  Ahoy::Engine.routes.draw do
6
6
  scope module: "ahoy" do
7
7
  resources :visits, only: [:create]
8
+ resources :events, only: [:create]
8
9
  end
9
10
  end
@@ -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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Ahoy
2
- VERSION = "0.1.8"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -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 && visitToken != "test") {
135
+ if (visitToken && visitorToken) {
71
136
  // TODO keep visit alive?
72
137
  log("Active visit");
73
138
  setReady();
74
139
  } else {
75
- setCookie("ahoy_visit", "test", 1);
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, function(response) {
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.setCookie = setCookie;
124
- ahoy.getCookie = getCookie;
125
- ahoy.destroyCookie = destroyCookie;
126
- ahoy.log = log;
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
- ahoy.ready = function (callback) {
129
- if (isReady) {
130
- callback();
131
- } else {
132
- queue.push(callback);
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.1.8
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 00:00:00.000000000 Z
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