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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2e6b98a3bbcd3ab67886e562a6a285344a1d0b53
4
- data.tar.gz: 97975b14612ca24bf380584f1020c39407a88894
3
+ metadata.gz: 7973efa4435f37d54dfa0bd84b7441473a4e3ddf
4
+ data.tar.gz: 3ceb16b3595ae8b258e63102ae996667652802af
5
5
  SHA512:
6
- metadata.gz: 3808dc8508cdbf29d1b018224179141d2588be09b76752035ddbb9f697ec22df873a0272de63e536575a6d887fcfee3997e9a9d3eddd7cfee02eafdbc68e8e9a
7
- data.tar.gz: d8c2b3764a85b9f66d0b06da755260e501c089fe3cab7d8a584cf4e167803714b103f1cf6b692eea242e3571ceabda097acb8285da9f88cb79f3213a4b8a3e79
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, campaign, landing page
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("campaign").sum(:revenue)
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 search engines
70
- - Gracefully degrades when cookies are disabled
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
- referring_uri = Addressable::URI.parse(params[:referrer]) rescue nil
18
- if referring_uri
19
- visit.referring_domain = referring_uri.host
20
- end
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}
@@ -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 ControllerExtensions
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
@@ -1,3 +1,3 @@
1
1
  module Ahoy
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
data/lib/ahoy_matey.rb CHANGED
@@ -1,8 +1,9 @@
1
1
  require "ahoy/version"
2
- require "ahoy/controller_extensions"
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::ControllerExtensions
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
- t.integer :user_id
7
- t.string :user_type
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 :campaign
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
- var expires = "; expires="+date.toGMTString();
26
+ date.setTime(date.getTime() + (ttl * 60 * 1000));
27
+ expires = "; expires=" + date.toGMTString();
25
28
  }
26
- else var expires = "";
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(var i=0;i < ca.length;i++) {
34
- var c = ca[i];
35
- while (c.charAt(0)==' ') c = c.substring(1,c.length);
36
- if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
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 (var i = 0; i < length; i++) {
50
- var randomNumber = Math.floor(Math.random() * chars.length);
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
- var visitToken = getCookie("ahoy_visit");
64
- var visitorToken = getCookie("ahoy_visitor");
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.3
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-26 00:00:00.000000000 Z
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/controller_extensions.rb
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