Added current_visitor_id method and switched to UUIDs

Andrew Kane committed Jun 12, 2014
commit 802a6054dc74928be039fb833d158ba82d073c0d
Showing 6 changed files with 111 additions and 95 deletions
CHANGELOG.md +3 -1
@@ @@ -1,5 +1,7 @@
- ## 0.2.3 [unreleased]
+ ## 0.3.0 [unreleased]
+ - Added `current_visitor_id` method
+ - Switched to UUIDs
- Quiet endpoint requests
- Skip server-side bot events
- Added `request` argument to `exclude_method`
app/controllers/ahoy/visits_controller.rb +2 -8
@@ @@ -2,8 +2,8 @@ module Ahoy
class VisitsController < BaseController
def create
- visit_token = params[:visit_token] || generate_token
- visitor_token = params[:visitor_token] || generate_token
+ visit_token = params[:visit_token] || Ahoy.generate_id
+ visitor_token = params[:visitor_token] || Ahoy.generate_id
visit =
Ahoy.visit_model.new do |v|
@@ @@ -23,11 +23,5 @@ module Ahoy
render json: {visit_token: visit.visit_token, visitor_token: visit.visitor_token}
end
- protected
-
- def generate_token
- SecureRandom.urlsafe_base64(32).gsub(/[\-_]/, "").first(32)
- end
-
end
end
ahoy.rb b/lib/ahoy.rb +66 -0
@@ @@ -0,0 +1,66 @@
+ require "addressable/uri"
+ require "browser"
+ require "geocoder"
+ require "referer-parser"
+ require "user_agent_parser"
+ require "request_store"
+ require "ahoy/version"
+ require "ahoy/tracker"
+ require "ahoy/controller"
+ require "ahoy/model"
+ require "ahoy/subscribers/active_record"
+ require "ahoy/engine"
+ require "ahoy/warden" if defined?(Warden)
+
+ module Ahoy
+
+ def self.generate_id
+ SecureRandom.uuid
+ end
+
+ def self.visit_model
+ @visit_model || ::Visit
+ end
+
+ def self.visit_model=(visit_model)
+ @visit_model = visit_model
+ end
+
+ # TODO private
+ # performance hack for referer-parser
+ def self.referrer_parser
+ @referrer_parser ||= RefererParser::Referer.new("https://github.com/ankane/ahoy")
+ end
+
+ # performance
+ def self.user_agent_parser
+ @user_agent_parser ||= UserAgentParser::Parser.new
+ end
+
+ def self.fetch_user(controller)
+ if user_method.respond_to?(:call)
+ user_method.call(controller)
+ else
+ controller.send(user_method)
+ end
+ end
+
+ mattr_accessor :user_method
+ self.user_method = proc do |controller|
+ (controller.respond_to?(:current_user) && controller.current_user) || (controller.respond_to?(:current_resource_owner, true) && controller.send(:current_resource_owner)) || nil
+ end
+
+ mattr_accessor :exclude_method
+
+ mattr_accessor :subscribers
+ self.subscribers = []
+
+ mattr_accessor :track_bots
+ self.track_bots = false
+
+ mattr_accessor :quiet
+ self.quiet = true
+ end
+
+ ActionController::Base.send :include, Ahoy::Controller
+ ActiveRecord::Base.send(:extend, Ahoy::Model) if defined?(ActiveRecord)
ahoy/controller.rb b/lib/ahoy/controller.rb +9 -0
@@ @@ -4,6 +4,7 @@ module Ahoy
def self.included(base)
base.helper_method :current_visit
base.helper_method :ahoy
+ base.before_filter :set_ahoy_visitor_cookie
base.before_filter do
RequestStore.store[:ahoy_controller] ||= self
end
@@ @@ -20,5 +21,13 @@ module Ahoy
@ahoy ||= Ahoy::Tracker.new(controller: self)
end
+ def set_ahoy_visitor_cookie
+ cookies[:ahoy_visitor] = current_visitor_id if !request.headers["Ahoy-Visitor"] && !cookies[:ahoy_visitor]
+ end
+
+ def current_visitor_id
+ @current_visit_id ||= request.headers["Ahoy-Visitor"] || cookies[:ahoy_visitor] || Ahoy.generate_id
+ end
+
end
end
ahoy_matey.rb b/lib/ahoy_matey.rb +1 -62
@@ @@ -1,62 +1 @@
- require "addressable/uri"
- require "browser"
- require "geocoder"
- require "referer-parser"
- require "user_agent_parser"
- require "request_store"
- require "ahoy/version"
- require "ahoy/tracker"
- require "ahoy/controller"
- require "ahoy/model"
- require "ahoy/subscribers/active_record"
- require "ahoy/engine"
- require "ahoy/warden" if defined?(Warden)
-
- module Ahoy
-
- def self.visit_model
- @visit_model || ::Visit
- end
-
- def self.visit_model=(visit_model)
- @visit_model = visit_model
- end
-
- # TODO private
- # performance hack for referer-parser
- def self.referrer_parser
- @referrer_parser ||= RefererParser::Referer.new("https://github.com/ankane/ahoy")
- end
-
- # performance
- def self.user_agent_parser
- @user_agent_parser ||= UserAgentParser::Parser.new
- end
-
- def self.fetch_user(controller)
- if user_method.respond_to?(:call)
- user_method.call(controller)
- else
- controller.send(user_method)
- end
- end
-
- mattr_accessor :user_method
- self.user_method = proc do |controller|
- (controller.respond_to?(:current_user) && controller.current_user) || (controller.respond_to?(:current_resource_owner, true) && controller.send(:current_resource_owner)) || nil
- end
-
- mattr_accessor :exclude_method
-
- mattr_accessor :subscribers
- self.subscribers = []
-
- mattr_accessor :track_bots
- self.track_bots = false
-
- mattr_accessor :quiet
- self.quiet = true
- end
-
- ActionController::Base.send :include, Ahoy::Controller
- ActiveRecord::Base.send(:extend, Ahoy::Model) if defined?(ActiveRecord)
+ require "ahoy"
vendor/assets/javascripts/ahoy.js +30 -24
@@ @@ -1,3 +1,11 @@
+ /*
+ * Ahoy.js
+ * Simple, powerful JavaScript analytics
+ * https://github.com/ankane/ahoy.js
+ * v0.1.0
+ * MIT License
+ */
+
/*jslint browser: true, indent: 2, plusplus: true, vars: true */
(function (window) {
@@ @@ -5,13 +13,14 @@
var ahoy = window.ahoy || window.Ahoy || {};
var $ = window.jQuery || window.Zepto || window.$;
- var visitToken, visitorToken;
+ var visitId, visitorId;
var visitTtl = 4 * 60; // 4 hours
var visitorTtl = 2 * 365 * 24 * 60; // 2 years
var isReady = false;
var queue = [];
var canStringify = typeof(JSON) !== "undefined" && typeof(JSON.stringify) !== "undefined";
var eventQueue = [];
+ var page = ahoy.page || window.location.pathname;
// cookies
@@ @@ -72,18 +81,12 @@
}
}
- // https://github.com/klughammer/node-randomstring
+ // http://stackoverflow.com/a/2117523/1177228
function generateId() {
- var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghiklmnopqrstuvwxyz';
- var length = 32;
- var string = '';
-
- for (var i = 0; i < length; i++) {
- var randomNumber = Math.floor(Math.random() * chars.length);
- string += chars.substring(randomNumber, randomNumber + 1);
- }
-
- return string;
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+ var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
+ return v.toString(16);
+ });
}
function saveEventQueue() {
@@ @@ -123,35 +126,37 @@
return {
tag: $target.get(0).tagName.toLowerCase(),
id: $target.attr("id"),
- "class": $target.attr("class")
+ "class": $target.attr("class"),
+ page: page,
+ section: $target.closest("*[data-section]").data("section")
};
}
// main
- visitToken = getCookie("ahoy_visit");
- visitorToken = getCookie("ahoy_visitor");
+ visitId = getCookie("ahoy_visit");
+ visitorId = getCookie("ahoy_visitor");
- if (visitToken && visitorToken) {
+ if (visitId && visitorId) {
// TODO keep visit alive?
log("Active visit");
setReady();
} else {
- visitToken = generateId();
- setCookie("ahoy_visit", visitToken, visitTtl);
+ visitId = generateId();
+ setCookie("ahoy_visit", visitId, visitTtl);
// make sure cookies are enabled
if (getCookie("ahoy_visit")) {
log("Visit started");
- if (!visitorToken) {
- visitorToken = generateId();
- setCookie("ahoy_visitor", visitorToken, visitorTtl);
+ if (!visitorId) {
+ visitorId = generateId();
+ setCookie("ahoy_visitor", visitorId, visitorTtl);
}
var data = {
- visit_token: visitToken,
- visitor_token: visitorToken,
+ visit_token: visitId,
+ visitor_token: visitorId,
platform: ahoy.platform || "Web",
landing_page: window.location.href,
screen_width: window.screen.width,
@@ @@ -209,7 +214,8 @@
ahoy.trackView = function () {
var properties = {
url: window.location.href,
- title: document.title
+ title: document.title,
+ page: page
};
ahoy.track("$view", properties);
};