ahoy_matey 0.1.2 → 0.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e8ac2f7e33c48f8b761a8ffee2ae5cd715e52849
4
- data.tar.gz: 7d069547085fb036b792492826c7a1fb81363367
3
+ metadata.gz: 5e7ae0f31293a7769778587395e0bd568e61f6f7
4
+ data.tar.gz: 8b941ee921205a3fd192b520934f7e57fb3ead7c
5
5
  SHA512:
6
- metadata.gz: 301bf689ed83f0f44a5c13cc4c1a53707e7ee5fbf7fe53936d560224a647c6d379be3c67834f15d5ec855d0f80081bd37dd4c6db4b9ab573c5ce3661902fb91c
7
- data.tar.gz: 3a3016d19a6f00750362bcd9a36992cb04b673bc77832c752cd4ea1fdc065e4faff8f06c38dbb628a9c078c291a0989cc15140966465a453708a572b42d4a31f
6
+ metadata.gz: e6d0bae8709e973024253730e1a95479e6effefca95356b89d88e0019f69eefa2b7eeb8a3ea194e9ef75f80e3011dd64e021f4b82fbba0bc7adea1738e81a212
7
+ data.tar.gz: 04abbb97db3428069c283284b07168188e69e98babd8e95eb93245a49da42ea753b46b91aa32d1d5a0f0867dcc5438f4fc93b22681d927326a7b38a1c53c329e
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 0.1.3
2
+
3
+ - Supports `current_user` from `ApplicationController`
4
+ - Added `ahoy.reset()`
5
+ - Added `ahoy.debug()`
6
+ - Added experimental support for native apps
7
+ - Prefer `ahoy` over `Ahoy`
8
+
1
9
  ## 0.1.2
2
10
 
3
11
  - Attach user on Devise sign up
data/README.md CHANGED
@@ -17,6 +17,30 @@ See which campaigns generate the most revenue effortlessly.
17
17
  Order.joins(:visit).group("utm_campaign").sum(:revenue)
18
18
  ```
19
19
 
20
+ ## Installation
21
+
22
+ Add this line to your application’s Gemfile:
23
+
24
+ ```ruby
25
+ gem 'ahoy_matey'
26
+ ```
27
+
28
+ And run the generator. This creates a model to store visits.
29
+
30
+ ```sh
31
+ rails generate ahoy:install
32
+ rake db:migrate
33
+ ```
34
+
35
+ Lastly, include the javascript file in `app/assets/javascripts/application.js` after jQuery.
36
+
37
+ ```javascript
38
+ //= require jquery
39
+ //= require ahoy
40
+ ```
41
+
42
+ We recommend using traditional analytics services like [Google Analytics](http://www.google.com/analytics/) as well.
43
+
20
44
  ## How It Works
21
45
 
22
46
  When someone visits your website, Ahoy creates a visit with lots of useful information.
@@ -65,13 +89,15 @@ Order.joins(:visit).group("device_type").count
65
89
 
66
90
  Ahoy automatically attaches the `current_user` to the `current_visit`.
67
91
 
92
+ If you define your own `current_user` method, be sure to add it to `ActionController::Base`, not `ApplicationController`.
93
+
68
94
  With [Devise](https://github.com/plataformatec/devise), it will attach the user even if he / she signs in after the visit starts.
69
95
 
70
96
  With other authentication frameworks, add this to the end of your sign in method:
71
97
 
72
98
  ```ruby
73
- if current_visit
74
- current_visit.user ||= current_user
99
+ if current_visit and !current_visit.user
100
+ current_visit.user = current_user
75
101
  current_visit.save!
76
102
  end
77
103
  ```
@@ -109,45 +135,64 @@ http://datakick.org/?utm_medium=twitter&utm_campaign=social&utm_source=tweet123
109
135
 
110
136
  Ahoy uses [Geocoder](https://github.com/alexreisner/geocoder) for IP-based geocoding.
111
137
 
112
- ### Multiple Subdomains [master]
138
+ ### Multiple Subdomains
113
139
 
114
- To track visits across multiple subdomains, add this to your layout **before** the javascript files.
140
+ To track visits across multiple subdomains, add this **before** the javascript files.
115
141
 
116
- ```html
117
- <script>
118
- var Ahoy = {"domain": "yourdomain.com"};
119
- </script>
142
+ ```javascript
143
+ var ahoy = {"domain": "yourdomain.com"};
120
144
  ```
121
145
 
122
- ### More
123
-
124
- - Excludes bots
125
- - Degrades gracefully when cookies are disabled
126
- - Don’t need a field? Just remove it from the migration
146
+ ### Development
127
147
 
128
- ## Installation
148
+ Ahoy is built with developers in mind. You can run the following code in your browser’s console.
129
149
 
130
- Add this line to your application’s Gemfile:
150
+ Force a new visit
131
151
 
132
- ```ruby
133
- gem 'ahoy_matey'
152
+ ```javascript
153
+ ahoy.reset(); // then reload the page
134
154
  ```
135
155
 
136
- And run the generator. This creates a model to store visits.
156
+ Log messages
137
157
 
138
- ```sh
139
- rails generate ahoy:install
140
- rake db:migrate
158
+ ```javascript
159
+ ahoy.debug();
141
160
  ```
142
161
 
143
- Lastly, include the javascript file in `app/assets/javascripts/application.js` after jQuery.
162
+ Turn off logging
144
163
 
145
164
  ```javascript
146
- //= require jquery
147
- //= require ahoy
165
+ ahoy.debug(false);
148
166
  ```
149
167
 
150
- We recommend using traditional analytics services like [Google Analytics](http://www.google.com/analytics/) as well.
168
+ ### Native Apps [experimental]
169
+
170
+ When a user launches the app, create a visit. Send a `POST` request to `/ahoy/visits` with:
171
+
172
+ - platform - `iOS`, `Android`, etc.
173
+ - app_version - `1.0.0`
174
+ - os_version - `7.0.6`
175
+ - visitor_token - if you have one
176
+
177
+ The endpoint will return a JSON response like:
178
+
179
+ ```json
180
+ {
181
+ "visit_token": "8tx2ziymkwa1WlppnkqxyaBaRlXrEQ3K",
182
+ "visitor_token": "hYBIV0rBfrIUAiArWweiECt4N9pyiygN"
183
+ }
184
+ ```
185
+
186
+ Send the visit token in the `Ahoy-Visit` header for all requests.
187
+
188
+ After 4 hours, create another visit and use the updated visit token.
189
+
190
+ ### More
191
+
192
+ - Excludes bots
193
+ - Degrades gracefully when cookies are disabled
194
+ - Don’t need a field? Just remove it from the migration
195
+ - Visits are 4 hours by default
151
196
 
152
197
  ## Reference
153
198
 
@@ -157,6 +202,12 @@ Use a different model
157
202
  Ahoy.visit_model = UserVisit
158
203
  ```
159
204
 
205
+ Change the platform on the web
206
+
207
+ ```javascript
208
+ var ahoy = {"platform": "Mobile Web"}
209
+ ```
210
+
160
211
  ## TODO
161
212
 
162
213
  - simple dashboard
@@ -1,25 +1,38 @@
1
1
  module Ahoy
2
- class VisitsController < ActionController::Base
2
+ class VisitsController < ApplicationController
3
+ # skip all filters
4
+ skip_filter *_process_action_callbacks.map(&:filter)
5
+
3
6
  before_filter :halt_bots
4
7
 
5
8
  def create
9
+ visit_token = generate_token
10
+ visitor_token = params[:visitor_token] || generate_token
11
+
6
12
  visit =
7
13
  Ahoy.visit_model.new do |v|
8
- v.visit_token = params[:visit_token]
9
- v.visitor_token = params[:visitor_token]
14
+ v.visit_token = visit_token
15
+ v.visitor_token = visitor_token
10
16
  v.ip = request.remote_ip if v.respond_to?(:ip=)
11
17
  v.user_agent = request.user_agent if v.respond_to?(:user_agent=)
12
18
  v.referrer = params[:referrer] if v.respond_to?(:referrer=)
13
19
  v.landing_page = params[:landing_page] if v.respond_to?(:landing_page=)
14
20
  v.user = current_user if respond_to?(:current_user) and v.respond_to?(:user=)
21
+ v.platform = params[:platform] if v.respond_to?(:platform=)
22
+ v.app_version = params[:app_version] if v.respond_to?(:app_version=)
23
+ v.os_version = params[:os_version] if v.respond_to?(:os_version=)
15
24
  end
16
25
 
17
26
  visit.save!
18
- render json: {id: visit.id}
27
+ render json: {visit_token: visit.visit_token, visitor_token: visit.visitor_token}
19
28
  end
20
29
 
21
30
  protected
22
31
 
32
+ def generate_token
33
+ SecureRandom.urlsafe_base64(32).gsub(/[\-_]/, "").first(32)
34
+ end
35
+
23
36
  def browser
24
37
  @browser ||= Browser.new(ua: request.user_agent)
25
38
  end
@@ -11,8 +11,9 @@ module Ahoy
11
11
  protected
12
12
 
13
13
  def current_visit
14
- if cookies[:ahoy_visit]
15
- @current_visit ||= Ahoy.visit_model.where(visit_token: cookies[:ahoy_visit]).first
14
+ visit_token = cookies[:ahoy_visit] || request.headers["Ahoy-Visit"]
15
+ if visit_token
16
+ @current_visit ||= Ahoy.visit_model.where(visit_token: visit_token).first
16
17
  end
17
18
  end
18
19
 
data/lib/ahoy/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ahoy
2
- VERSION = "0.1.2"
2
+ VERSION = "0.1.3"
3
3
  end
data/lib/ahoy_matey.rb CHANGED
@@ -31,10 +31,11 @@ ActiveRecord::Base.send(:extend, Ahoy::Model) if defined?(ActiveRecord)
31
31
 
32
32
  if defined?(Warden)
33
33
  Warden::Manager.after_set_user except: :fetch do |user, auth, opts|
34
- request = Rack::Request.new(auth.env)
35
- if request.cookies["ahoy_visit"]
36
- visit = Ahoy.visit_model.where(visit_token: request.cookies["ahoy_visit"]).first
37
- if visit
34
+ request = ActionDispatch::Request.new(auth.env)
35
+ visit_token = request.cookies["ahoy_visit"] || request.headers["Ahoy-Visit"]
36
+ if visit_token
37
+ visit = Ahoy.visit_model.where(visit_token: visit_token).first
38
+ if visit and !visit.user
38
39
  visit.user = user
39
40
  visit.save!
40
41
  end
@@ -39,6 +39,11 @@ class <%= migration_class_name %> < ActiveRecord::Migration
39
39
  t.string :utm_content
40
40
  t.string :utm_campaign
41
41
 
42
+ # native apps
43
+ # t.string :platform
44
+ # t.string :app_version
45
+ # t.string :os_version
46
+
42
47
  t.timestamp :created_at
43
48
  end
44
49
 
@@ -3,24 +3,16 @@
3
3
  (function (window) {
4
4
  "use strict";
5
5
 
6
- var debugMode = false;
7
- var options = window.Ahoy || {};
6
+ var ahoy = window.ahoy || window.Ahoy || {};
8
7
  var $ = window.jQuery || window.Zepto || window.$;
9
8
  var visitToken, visitorToken;
10
- var visitTtl, visitorTtl;
11
-
12
- if (debugMode) {
13
- visitTtl = 0.2;
14
- visitorTtl = 5; // 5 minutes
15
- } else {
16
- visitTtl = 4 * 60; // 4 hours
17
- visitorTtl = 2 * 365 * 24 * 60; // 2 years
18
- }
9
+ var visitTtl = 4 * 60; // 4 hours
10
+ var visitorTtl = 2 * 365 * 24 * 60; // 2 years
19
11
 
20
12
  // cookies
21
13
 
22
14
  // http://www.quirksmode.org/js/cookies.html
23
- function setCookie(name, value, ttl, domain) {
15
+ function setCookie(name, value, ttl) {
24
16
  var expires = "";
25
17
  var cookieDomain = "";
26
18
  if (ttl) {
@@ -28,8 +20,8 @@
28
20
  date.setTime(date.getTime() + (ttl * 60 * 1000));
29
21
  expires = "; expires=" + date.toGMTString();
30
22
  }
31
- if (domain) {
32
- cookieDomain = "; domain=" + domain;
23
+ if (ahoy.domain) {
24
+ cookieDomain = "; domain=" + ahoy.domain;
33
25
  }
34
26
  document.cookie = name + "=" + value + expires + cookieDomain + "; path=/";
35
27
  }
@@ -50,26 +42,13 @@
50
42
  return null;
51
43
  }
52
44
 
53
- // ids
54
-
55
- // https://github.com/klughammer/node-randomstring
56
- function generateToken() {
57
- var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghiklmnopqrstuvwxyz';
58
- var length = 32;
59
- var string = '';
60
- var i, randomNumber;
61
-
62
- for (i = 0; i < length; i++) {
63
- randomNumber = Math.floor(Math.random() * chars.length);
64
- string += chars.substring(randomNumber, randomNumber + 1);
65
- }
66
-
67
- return string;
45
+ function destroyCookie(name) {
46
+ setCookie(name, "", -1);
68
47
  }
69
48
 
70
- function debug(message) {
71
- if (debugMode) {
72
- window.console.log(message, visitToken, visitorToken);
49
+ function log(message) {
50
+ if (getCookie("ahoy_debug")) {
51
+ window.console.log(message);
73
52
  }
74
53
  }
75
54
 
@@ -78,26 +57,18 @@
78
57
  visitToken = getCookie("ahoy_visit");
79
58
  visitorToken = getCookie("ahoy_visitor");
80
59
 
81
- if (visitToken && visitorToken) {
60
+ if (visitToken && visitorToken && visitToken != "test") {
82
61
  // TODO keep visit alive?
83
- debug("Active visit");
62
+ log("Active visit");
84
63
  } else {
85
- if (!visitorToken) {
86
- visitorToken = generateToken();
87
- setCookie("ahoy_visitor", visitorToken, visitorTtl, options.domain);
88
- }
89
-
90
- // always generate a new visit id here
91
- visitToken = generateToken();
92
- setCookie("ahoy_visit", visitToken, visitTtl, options.domain);
64
+ setCookie("ahoy_visit", "test", 1);
93
65
 
94
66
  // make sure cookies are enabled
95
67
  if (getCookie("ahoy_visit")) {
96
- debug("Visit started");
68
+ log("Visit started");
97
69
 
98
70
  var data = {
99
- visit_token: visitToken,
100
- visitor_token: visitorToken,
71
+ platform: ahoy.platform || "Web",
101
72
  landing_page: window.location.href
102
73
  };
103
74
 
@@ -106,12 +77,35 @@
106
77
  data.referrer = document.referrer;
107
78
  }
108
79
 
109
- debug(data);
80
+ if (visitorToken) {
81
+ data.visitor_token = visitorToken;
82
+ }
83
+
84
+ log(data);
110
85
 
111
- $.post("/ahoy/visits", data);
86
+ $.post("/ahoy/visits", data, function(response) {
87
+ setCookie("ahoy_visit", response.visit_token, visitTtl);
88
+ setCookie("ahoy_visitor", response.visitor_token, visitorTtl);
89
+ }, "json");
112
90
  } else {
113
- debug("Cookies disabled");
91
+ log("Cookies disabled");
114
92
  }
115
93
  }
116
94
 
95
+ ahoy.reset = function () {
96
+ destroyCookie("ahoy_visit");
97
+ destroyCookie("ahoy_visitor");
98
+ return true;
99
+ };
100
+
101
+ ahoy.debug = function (enabled) {
102
+ if (enabled === false) {
103
+ destroyCookie("ahoy_debug");
104
+ } else {
105
+ setCookie("ahoy_debug", "t", 365 * 24 * 60); // 1 year
106
+ }
107
+ return true;
108
+ };
109
+
110
+ window.ahoy = ahoy;
117
111
  }(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.2
4
+ version: 0.1.3
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-04-16 00:00:00.000000000 Z
11
+ date: 2014-04-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: addressable