class TrackableAction < TrackableBase # Mongoid Config ================================================================================= include Mongoid::Document include Mongoid::Timestamps field :kind field :label field :referrer field :url field :relative_url field :site field :new_visit, :type => Boolean index :kind, :unique => false index :label, :unique => false index :url, :unique => false index :site, :unique => false referenced_in :trackable_session # Scopes ========================================================================================= scope :by_kind, lambda { |k| { :where => { :kind => k } } } scope :by_label, lambda { |l| { :where => { :label => l } } } scope :clicks, :where => {:kind => 'click'} scope :clickthroughs, :where => {:kind => 'clickthrough'} scope :conversions, :where => {:kind => 'conversion'} scope :leads, :where => {:kind => 'conversion'} scope :for_site, lambda { |s| { :where => { :site => s } } } scope :for_month, lambda { |d| { :where => { :created_at => { '$gte' => d.beginning_of_month, '$lte' => d.end_of_month } } } } scope :for_week, lambda { |d| { :where => { :created_at => { '$gte' => d.beginning_of_week, '$lte' => d.end_of_week } } } } scope :for_date_range, lambda { |start_date,end_date| { :where => { :created_at => { '$gte' => start_date.beginning_of_month, '$lte' => end_date.end_of_month } } } } scope :mouseovers, :where => {:kind => 'mouseover'} scope :scrolls, :where => {:kind => 'scroll'} scope :views, :where => {:kind => 'view'} # Constants ====================================================================================== KINDS = ['clicks', 'leads', 'scrolls', 'mouseovers', 'clickthroughs'] # Class Methods ================================================================================== # Create a tracked action from the specified arguments. The action finds an existing session or creates a new one. # # ==== Attributes # # * +:params+ - {:site => 'foo.com', :referrer => 'cnn.com/foo', :url => '/cnn'} # * +:creation_date+ - action's creation date (used for testing) # # ==== Examples # # TrackableAction.create_from_params( :site => 'foo.com' ) def self.create_from_params(params, creation_date = Time.zone.now) _referring_site = nil _relative_url = nil # Some govt URLs break URI.parse, so wrap in a begin/rescue block 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.where(:session_id => params[:session_id]).first 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 = trackable_session.trackable_actions.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 for all actions that have already been tracked, used to populate report filters. def self.kinds TrackableAction.all.map{|ta| ta.kind}.uniq.sort - ['view'] end # Returns a histogram for visited pages in the specified site(s). # # ==== Attributes # # * +:action_kind+ - kind of action: 'clicks', 'leads', 'scrolls', 'mouseovers', 'clickthroughs' # * +:site+ - name of a site # * +:time_period+ - date range as a string: 'past 3 months', 'past 6 months', 'past 12 months' # * +:visit_kind+ - kind of visit as a string: 'direct', 'natural', 'paid', 'search' # # ==== Examples # # TrackableAction.pages_histogram( :site => 'foo.com' ) def self.pages_histogram(args) conditions = TrackableAction.search(args).selector TrackableAction.collection.group(:keyf => "function(x) { return { url: x.url }; }", :cond => conditions, :initial => { :count => 0}, :reduce => "function(x,y){y.count++}").inject({}){|h,k| k['url'] ||= '/'; 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 # Returns a scope based on time period, site, and visit kind. Null arguments returns all. # # ==== Attributes # # * +:action_kind+ - kind of action: 'clicks', 'leads', 'scrolls', 'mouseovers', 'clickthroughs' # * +:site+ - name of a site # * +:time_period+ - date range as a string: 'past 3 months', 'past 6 months', 'past 12 months' # * +:visit_kind+ - kind of visit as a string: 'direct', 'natural', 'paid', 'search' # # ==== Examples # # TrackableAction.pages_histogram( :site => 'foo.com' ) def self.search(args = {}) args[:site] ||= 'all sites' args[:action_kind] ||= 'views' args[:action_kind] == 'views' unless TrackableAction::KINDS.include?(args[:action_kind]) [:site, :action_kind, :time_period, :visit_kind].each{|a| args[a] = args[a].downcase if args[a]} (args[:start_date], args[:end_date]) = dates_from_time_period(args[:time_period]) sessions = TrackableSession.search(args).map{|s| s.id.to_s} actions = TrackableAction.where(:trackable_session_id.in => sessions) actions = actions.send("#{args[:action_kind]}") actions end # Returns a scope based on action kind, site, and visit kind only. # # ==== Attributes # # * +:action_kind+ - kind of action: 'clicks', 'leads', 'scrolls', 'mouseovers', 'clickthroughs' # * +:site+ - name of a site # * +:visit_kind+ - kind of visit as a string: 'direct', 'natural', 'paid', 'search' # # ==== Examples # # TrackableAction.search_without_date( :site => 'foo.com' ) def self.search_without_date(args = {}) args = args.clone args.delete(:time_period) self.search(args) 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