ahoy_matey 0.1.2 → 0.1.3

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: 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