ahoy_matey 0.0.3 → 0.0.4
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/README.md +8 -5
- data/ahoy_matey.gemspec +1 -0
- data/app/controllers/ahoy/visits_controller.rb +4 -52
- data/app/models/ahoy/visit.rb +66 -0
- data/lib/ahoy/{controller_extensions.rb → controller.rb} +1 -8
- data/lib/ahoy/version.rb +1 -1
- data/lib/ahoy_matey.rb +17 -2
- data/lib/generators/ahoy/templates/install.rb +17 -5
- data/vendor/assets/javascripts/ahoy.js +23 -15
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7973efa4435f37d54dfa0bd84b7441473a4e3ddf
|
4
|
+
data.tar.gz: 3ceb16b3595ae8b258e63102ae996667652802af
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a16bd0b6d30f134a901d2574bc944d411e049e1a7fcaae46707245a98287013b2e4c26c69eca8fd77cf00394e34bd6576843b62d85fc7d93e92344565e7e58a1
|
7
|
+
data.tar.gz: 6c228da084f4949c9fbd8618b1fdc2a04f83a75402d3f2eadbba954f6f02988b040b223181f4b7a34e5ec6d5e375c218a367ceb3457239966bff877b8b564503
|
data/README.md
CHANGED
@@ -4,16 +4,17 @@
|
|
4
4
|
|
5
5
|
In under a minute, start learning more about your visitors.
|
6
6
|
|
7
|
-
- traffic source - referrer, referring domain,
|
7
|
+
- traffic source - referrer, referring domain, landing page, search keyword
|
8
8
|
- location - country, region, and city
|
9
9
|
- technology - browser, OS, and device type
|
10
|
+
- utm parameters - source, medium, term, content, campaign
|
10
11
|
|
11
12
|
It’s all stored in **your database** so you can easily combine it with other data.
|
12
13
|
|
13
14
|
See which campaigns generate the most revenue effortlessly.
|
14
15
|
|
15
16
|
```ruby
|
16
|
-
Order.joins(:visit).group("
|
17
|
+
Order.joins(:visit).group("utm_campaign").sum(:revenue)
|
17
18
|
```
|
18
19
|
|
19
20
|
## Ready, Set, Go
|
@@ -66,8 +67,8 @@ Order.joins(:visit).group("city").count
|
|
66
67
|
|
67
68
|
## Features
|
68
69
|
|
69
|
-
- Excludes
|
70
|
-
-
|
70
|
+
- Excludes bots
|
71
|
+
- Degrades gracefully when cookies are disabled
|
71
72
|
- Gets campaign from utm_campaign parameter
|
72
73
|
|
73
74
|
## TODO
|
@@ -75,8 +76,10 @@ Order.joins(:visit).group("city").count
|
|
75
76
|
- better readme
|
76
77
|
- model integration
|
77
78
|
- update visit when user logs in
|
78
|
-
- better browser / OS detection
|
79
79
|
- set visit_id automatically on `visitable` models
|
80
|
+
- simple dashboard
|
81
|
+
- hook to store additional fields
|
82
|
+
- turn off modules
|
80
83
|
|
81
84
|
## Contributing
|
82
85
|
|
data/ahoy_matey.gemspec
CHANGED
@@ -21,6 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.add_dependency "addressable"
|
22
22
|
spec.add_dependency "browser", ">= 0.4.0"
|
23
23
|
spec.add_dependency "geocoder"
|
24
|
+
spec.add_dependency "referer-parser"
|
24
25
|
|
25
26
|
spec.add_development_dependency "bundler", "~> 1.5"
|
26
27
|
spec.add_development_dependency "rake"
|
@@ -14,58 +14,10 @@ module Ahoy
|
|
14
14
|
v.user = current_user if respond_to?(:current_user)
|
15
15
|
end
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
landing_uri = Addressable::URI.parse(params[:landing_page]) rescue nil
|
23
|
-
if landing_uri
|
24
|
-
visit.campaign = (landing_uri.query_values || {})["utm_campaign"]
|
25
|
-
end
|
26
|
-
|
27
|
-
visit.browser = browser.name
|
28
|
-
|
29
|
-
# TODO add more
|
30
|
-
visit.os =
|
31
|
-
if browser.android?
|
32
|
-
"Android"
|
33
|
-
elsif browser.ios?
|
34
|
-
"iOS"
|
35
|
-
elsif browser.windows_phone?
|
36
|
-
"Windows Phone"
|
37
|
-
elsif browser.blackberry?
|
38
|
-
"Blackberry"
|
39
|
-
elsif browser.chrome_os?
|
40
|
-
"Chrome OS"
|
41
|
-
elsif browser.mac?
|
42
|
-
"Mac"
|
43
|
-
elsif browser.windows?
|
44
|
-
"Windows"
|
45
|
-
elsif browser.linux?
|
46
|
-
"Linux"
|
47
|
-
end
|
48
|
-
|
49
|
-
visit.device_type =
|
50
|
-
if browser.tv?
|
51
|
-
"TV"
|
52
|
-
elsif browser.console?
|
53
|
-
"Console"
|
54
|
-
elsif browser.tablet?
|
55
|
-
"Tablet"
|
56
|
-
elsif browser.mobile?
|
57
|
-
"Mobile"
|
58
|
-
else
|
59
|
-
"Desktop"
|
60
|
-
end
|
61
|
-
|
62
|
-
# location
|
63
|
-
location = Geocoder.search(request.remote_ip).first rescue nil
|
64
|
-
if location
|
65
|
-
visit.country = location.country.presence
|
66
|
-
visit.region = location.state.presence
|
67
|
-
visit.city = location.city.presence
|
68
|
-
end
|
17
|
+
visit.set_traffic_source
|
18
|
+
visit.set_technology
|
19
|
+
visit.set_location
|
20
|
+
visit.set_utm_parameters
|
69
21
|
|
70
22
|
visit.save!
|
71
23
|
render json: {id: visit.id}
|
data/app/models/ahoy/visit.rb
CHANGED
@@ -1,5 +1,71 @@
|
|
1
1
|
module Ahoy
|
2
2
|
class Visit < ActiveRecord::Base
|
3
3
|
belongs_to :user, polymorphic: true
|
4
|
+
|
5
|
+
def set_traffic_source
|
6
|
+
referring_uri = Addressable::URI.parse(referrer) rescue nil
|
7
|
+
self.referring_domain = referring_uri.try(:host)
|
8
|
+
search_keyword = RefererParser::Referer.new(referrer).search_term rescue nil
|
9
|
+
self.search_keyword = search_keyword.present? ? search_keyword : nil
|
10
|
+
end
|
11
|
+
|
12
|
+
def set_utm_parameters
|
13
|
+
landing_uri = Addressable::URI.parse(landing_page) rescue nil
|
14
|
+
if landing_uri
|
15
|
+
query_values = landing_uri.query_values || {}
|
16
|
+
%w[utm_source utm_medium utm_term utm_content utm_campaign].each do |name|
|
17
|
+
self[name] = query_values[name]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def set_technology
|
23
|
+
browser = Browser.new(ua: user_agent)
|
24
|
+
|
25
|
+
self.browser = browser.name
|
26
|
+
|
27
|
+
# TODO add more
|
28
|
+
self.os =
|
29
|
+
if browser.android?
|
30
|
+
"Android"
|
31
|
+
elsif browser.ios?
|
32
|
+
"iOS"
|
33
|
+
elsif browser.windows_phone?
|
34
|
+
"Windows Phone"
|
35
|
+
elsif browser.blackberry?
|
36
|
+
"Blackberry"
|
37
|
+
elsif browser.chrome_os?
|
38
|
+
"Chrome OS"
|
39
|
+
elsif browser.mac?
|
40
|
+
"Mac"
|
41
|
+
elsif browser.windows?
|
42
|
+
"Windows"
|
43
|
+
elsif browser.linux?
|
44
|
+
"Linux"
|
45
|
+
end
|
46
|
+
|
47
|
+
self.device_type =
|
48
|
+
if browser.tv?
|
49
|
+
"TV"
|
50
|
+
elsif browser.console?
|
51
|
+
"Console"
|
52
|
+
elsif browser.tablet?
|
53
|
+
"Tablet"
|
54
|
+
elsif browser.mobile?
|
55
|
+
"Mobile"
|
56
|
+
else
|
57
|
+
"Desktop"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def set_location
|
62
|
+
location = Geocoder.search(ip).first rescue nil
|
63
|
+
if location
|
64
|
+
self.country = location.country.presence
|
65
|
+
self.region = location.state.presence
|
66
|
+
self.city = location.city.presence
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
4
70
|
end
|
5
71
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Ahoy
|
2
|
-
module
|
2
|
+
module Controller
|
3
3
|
|
4
4
|
def self.included(base)
|
5
5
|
base.helper_method :current_visit
|
@@ -10,13 +10,6 @@ module Ahoy
|
|
10
10
|
def current_visit
|
11
11
|
if cookies[:ahoy_visit]
|
12
12
|
@current_visit ||= Ahoy::Visit.where(visit_token: cookies[:ahoy_visit]).first
|
13
|
-
if @current_visit
|
14
|
-
@current_visit
|
15
|
-
else
|
16
|
-
# clear cookie if visits are destroyed
|
17
|
-
cookies.delete(:ahoy_visit)
|
18
|
-
nil
|
19
|
-
end
|
20
13
|
end
|
21
14
|
end
|
22
15
|
|
data/lib/ahoy/version.rb
CHANGED
data/lib/ahoy_matey.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
require "ahoy/version"
|
2
|
-
require "ahoy/
|
2
|
+
require "ahoy/controller"
|
3
3
|
require "addressable/uri"
|
4
4
|
require "browser"
|
5
5
|
require "geocoder"
|
6
|
+
require "referer-parser"
|
6
7
|
|
7
8
|
module Ahoy
|
8
9
|
class Engine < ::Rails::Engine
|
@@ -10,4 +11,18 @@ module Ahoy
|
|
10
11
|
end
|
11
12
|
end
|
12
13
|
|
13
|
-
ActionController::Base.send :include, Ahoy::
|
14
|
+
ActionController::Base.send :include, Ahoy::Controller
|
15
|
+
|
16
|
+
if defined?(Warden)
|
17
|
+
Warden::Manager.after_authentication do |user, auth, opts|
|
18
|
+
p user
|
19
|
+
p auth.env
|
20
|
+
p opts
|
21
|
+
request = Rack::Request.new(auth.env)
|
22
|
+
if request.cookies["ahoy_visit"]
|
23
|
+
visit = Ahoy::Visit.where(visit_token: request.cookies["ahoy_visit"]).first
|
24
|
+
visit.user = user
|
25
|
+
visit.save!
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -1,18 +1,23 @@
|
|
1
1
|
class <%= migration_class_name %> < ActiveRecord::Migration
|
2
2
|
def change
|
3
3
|
create_table :ahoy_visits do |t|
|
4
|
+
# cookies
|
4
5
|
t.string :visit_token
|
5
6
|
t.string :visitor_token
|
6
|
-
|
7
|
-
|
7
|
+
|
8
|
+
# standard
|
8
9
|
t.string :ip
|
9
10
|
t.text :user_agent
|
11
|
+
t.text :referrer
|
12
|
+
t.text :landing_page
|
13
|
+
|
14
|
+
# user
|
15
|
+
t.integer :user_id
|
16
|
+
t.string :user_type
|
10
17
|
|
11
18
|
# traffic source
|
12
|
-
t.text :referrer
|
13
19
|
t.string :referring_domain
|
14
|
-
t.string :
|
15
|
-
t.text :landing_page
|
20
|
+
t.string :search_keyword
|
16
21
|
|
17
22
|
# technology
|
18
23
|
t.string :browser
|
@@ -24,6 +29,13 @@ class <%= migration_class_name %> < ActiveRecord::Migration
|
|
24
29
|
t.string :region
|
25
30
|
t.string :city
|
26
31
|
|
32
|
+
# utm parameters
|
33
|
+
t.string :utm_source
|
34
|
+
t.string :utm_medium
|
35
|
+
t.string :utm_term
|
36
|
+
t.string :utm_content
|
37
|
+
t.string :utm_campaign
|
38
|
+
|
27
39
|
t.timestamp :created_at
|
28
40
|
end
|
29
41
|
|
@@ -1,10 +1,12 @@
|
|
1
1
|
/*jslint browser: true, indent: 2, plusplus: true, vars: true */
|
2
2
|
|
3
|
-
(function () {
|
3
|
+
(function (window) {
|
4
4
|
"use strict";
|
5
5
|
|
6
6
|
var debugMode = false;
|
7
7
|
var visitTtl, visitorTtl;
|
8
|
+
var $ = window.jQuery || window.Zepto || window.$;
|
9
|
+
var visitToken, visitorToken;
|
8
10
|
|
9
11
|
if (debugMode) {
|
10
12
|
visitTtl = 0.2;
|
@@ -18,22 +20,27 @@
|
|
18
20
|
|
19
21
|
// http://www.quirksmode.org/js/cookies.html
|
20
22
|
function setCookie(name, value, ttl) {
|
23
|
+
var expires = "";
|
21
24
|
if (ttl) {
|
22
25
|
var date = new Date();
|
23
|
-
date.setTime(date.getTime()+(ttl*60*1000));
|
24
|
-
|
26
|
+
date.setTime(date.getTime() + (ttl * 60 * 1000));
|
27
|
+
expires = "; expires=" + date.toGMTString();
|
25
28
|
}
|
26
|
-
|
27
|
-
document.cookie = name+"="+value+expires+"; path=/";
|
29
|
+
document.cookie = name + "=" + value + expires + "; path=/";
|
28
30
|
}
|
29
31
|
|
30
32
|
function getCookie(name) {
|
33
|
+
var i, c;
|
31
34
|
var nameEQ = name + "=";
|
32
35
|
var ca = document.cookie.split(';');
|
33
|
-
for(
|
34
|
-
|
35
|
-
while (c.charAt(0)
|
36
|
-
|
36
|
+
for (i = 0; i < ca.length; i++) {
|
37
|
+
c = ca[i];
|
38
|
+
while (c.charAt(0) === ' ') {
|
39
|
+
c = c.substring(1, c.length);
|
40
|
+
}
|
41
|
+
if (c.indexOf(nameEQ) === 0) {
|
42
|
+
return c.substring(nameEQ.length, c.length);
|
43
|
+
}
|
37
44
|
}
|
38
45
|
return null;
|
39
46
|
}
|
@@ -45,9 +52,10 @@
|
|
45
52
|
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghiklmnopqrstuvwxyz';
|
46
53
|
var length = 32;
|
47
54
|
var string = '';
|
55
|
+
var i, randomNumber;
|
48
56
|
|
49
|
-
for (
|
50
|
-
|
57
|
+
for (i = 0; i < length; i++) {
|
58
|
+
randomNumber = Math.floor(Math.random() * chars.length);
|
51
59
|
string += chars.substring(randomNumber, randomNumber + 1);
|
52
60
|
}
|
53
61
|
|
@@ -55,13 +63,13 @@
|
|
55
63
|
}
|
56
64
|
|
57
65
|
function debug(message) {
|
58
|
-
console.log(message, visitToken, visitorToken);
|
66
|
+
window.console.log(message, visitToken, visitorToken);
|
59
67
|
}
|
60
68
|
|
61
69
|
// main
|
62
70
|
|
63
|
-
|
64
|
-
|
71
|
+
visitToken = getCookie("ahoy_visit");
|
72
|
+
visitorToken = getCookie("ahoy_visitor");
|
65
73
|
|
66
74
|
if (visitToken && visitorToken) {
|
67
75
|
// TODO keep visit alive?
|
@@ -99,4 +107,4 @@
|
|
99
107
|
}
|
100
108
|
}
|
101
109
|
|
102
|
-
}());
|
110
|
+
}(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.0.
|
4
|
+
version: 0.0.4
|
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-02
|
11
|
+
date: 2014-03-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: referer-parser
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: bundler
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -96,7 +110,7 @@ files:
|
|
96
110
|
- app/controllers/ahoy/visits_controller.rb
|
97
111
|
- app/models/ahoy/visit.rb
|
98
112
|
- config/routes.rb
|
99
|
-
- lib/ahoy/
|
113
|
+
- lib/ahoy/controller.rb
|
100
114
|
- lib/ahoy/version.rb
|
101
115
|
- lib/ahoy_matey.rb
|
102
116
|
- lib/generators/ahoy/install_generator.rb
|