class TrackableAction include MongoMapper::Document # MongoMapper Setup ============================================================================== belongs_to :trackable_session key :trackable_session_id, ObjectId key :kind, String, :index => true key :label, String, :index => true key :referrer, String key :url, String, :index => true key :relative_url, String key :site, String, :index => true key :new_visit, Boolean timestamps! # Scopes ========================================================================================= scope :by_kind, lambda { |k| { :conditions => { :kind => k } } } scope :by_label, lambda { |l| { :conditions => { :label => l } } } scope :clicks, :conditions => {:kind => 'click'} scope :clickthroughs, :conditions => {:kind => 'clickthrough'} scope :conversions, :conditions => {:kind => 'conversion'} scope :leads, :conditions => {:kind => 'conversion'} scope :for_site, lambda { |s| { :conditions => { :site => s } } } scope :for_month, lambda { |d| { :conditions => { :created_at => { '$gte' => d.beginning_of_month, '$lte' => d.end_of_month } } } } scope :for_week, lambda { |d| { :conditions => { :created_at => { '$gte' => d.beginning_of_week, '$lte' => d.end_of_week } } } } scope :for_date_range, lambda { |start_date,end_date| { :conditions => { :created_at => { '$gte' => start_date.beginning_of_month, '$lte' => end_date.end_of_month } } } } scope :mouseovers, :conditions => {:kind => 'mouseover'} scope :scrolls, :conditions => {:kind => 'scroll'} scope :views, :conditions => {:kind => 'view'} # Constants ====================================================================================== KINDS = ['clicks', 'leads', 'scrolls', 'mouseovers', 'clickthroughs'] # Class Methods ================================================================================== def self.create_from_params(params, creation_date = Time.zone.now) _referring_site = nil _relative_url = nil begin if ! params[:referrer].blank? && params[:referrer] != '/' _referring_site = URI.parse(params[:referrer]).host _referring_site = nil if _referring_site == params[:site] end _relative_url = URI.parse(params[:url]).path.downcase rescue end unless trackable_session = TrackableSession.find_by_session_id(params[:session_id]) trackable_session = TrackableSession.create( :session_id => params[:session_id], :referrer => _referring_site, :referring_keywords => params[:referring_keywords], :ip_address => params[:remote_ip], :site => params[:site].downcase, :session_id => params[:session_id], :initial_request_url => params[:url].downcase, :entrance_page => _relative_url, :exit_page => _relative_url, :user_agent => params[:user_agent], :views_count => 0, :created_at => creation_date ) end _action = TrackableAction.create( :kind => params[:kind], :label => params[:label], :referrer => params[:referrer], :url => params[:url], :relative_url => _relative_url, :site => params[:site], :trackable_session_id => trackable_session.id, :created_at => creation_date ) trackable_session.touch(params[:kind], params[:destination], _relative_url) _action end def self.create_test_data!(count = 1000, destructive = true) if destructive TrackableStat.delete_all TrackableSession.delete_all TrackableAction.delete_all end 1..count.times do params = { :remote_ip => "127.0.0.#{rand(128)}", :site => ['www.test1.com', 'www.test2.com', 'www.test3.com'].rand, :initial_referrer => ['','','','','','http://www.google.com','http://www.bing.com','http://www.yahoo.com','http://www.seologic.com','http://www.idolhands.com','http://www.findcounseling.com','http://www.emeritus.com'].rand, :session_id => "#{rand(10000)}#{('a'..'z').to_a.rand}" } created_at = Time.zone.now - rand(6).months - rand(30).days (1..rand(10)).each do |i| params[:kind] = ['view','view','mouseover','click','view','view','scroll','view','click','conversion'].rand params[:referrer] = i == 1 ? params[:initial_referrer] : "/" params[:referring_keywords] = i == 1 ? ['foo','bar','trouble','braids'].rand : nil params[:url] = "http://#{params[:site]}#{['/','/about','/tour','/contact','/services'].rand}" params[:label] = params[:kind].titleize TrackableAction.create_from_params(params, created_at + i.minutes) end end "Created #{count} sample sessions." end # Returns a list of kinds that have already been tracked. def self.kinds _kinds = [] KINDS.each{ |kind| _kinds << kind unless self.send(kind).count.zero? } _kinds end def self.pages_histogram(args) TrackableAction.collection.group("function(x) { return { url: x.url }; }", TrackableAction.search(args).to_hash, { :count => 0}, "function(x,y){y.count++}", true).inject({}){|h,k| h[URI.parse(k['url']).path] ||= 0; h[URI.parse(k['url']).path] += k['count']; h}.sort{|a,b| a[1] <=> b[1]}.reverse end def self.search(args = {}) args[:site] ||= 'all sites' args[:action_kind] ||= 'views' [:site, :action_kind, :time_period].each{|a| args[a] = args[a].downcase if args[a]} case args[:time_period] when 'past 3 months' args[:start_date] = (Time.zone.now - 2.months).beginning_of_month args[:end_date] = Time.zone.now when 'past 6 months' args[:start_date] = (Time.zone.now - 5.months).beginning_of_month args[:end_date] = Time.zone.now when 'past 12 months' args[:start_date] = (Time.zone.now - 11.months).beginning_of_month args[:end_date] = Time.zone.now else args[:start_date] = TrackableAction.first.created_at args[:end_date] = Time.zone.now end if args[:time_period] if args[:site] == 'all sites' TrackableAction.send("#{args[:action_kind]}").for_date_range(args[:start_date], args[:end_date]) else TrackableAction.for_site(args[:site]).send("#{args[:action_kind]}").for_date_range(args[:start_date], args[:end_date]) end else if args[:site] == 'all sites' TrackableAction.send("#{args[:action_kind]}") else TrackableAction.for_site(args[:site]).send("#{args[:action_kind]}") end end end # Can't combine date conditions, so this is needed for reports def self.search_without_date(args = {}) args[:site] ||= 'all sites' args[:action_kind] ||= 'views' [:site, :action_kind, :visit_kind].each{|a| args[a] = args[a].downcase} if args[:site] == 'all sites' TrackableAction.send("#{args[:action_kind]}") else TrackableAction.for_site(args[:site]).send("#{args[:action_kind]}") end end # Instance Methods =============================================================================== def click? self.kind == 'click' end def clickthrough? self.kind == 'clickthrough' end def conversion? self.kind == 'conversion' end def mouseover? self.kind == 'mouseover' end def scroll? self.kind == 'scroll' end def view? self.kind == 'view' end end