Monday, 5 November 2012

How question view counts are handled in Shapado

Shapado has a feature which lets its users display how many times a question has been viewed. The view count does not take into account repeated views from a single IP address and, hence, it records the number of unique viewers a question has received.

How it is implemented

The Question class contains an instance variable called views_count which keeps track of the number of views an instance of a question has received. To track this information, Question implements a method called viewed! which takes the IP address of the viewer as an input parameter. The view method, in turn, uses a class called ViewsCount to keep track of individual views from different IPs. When the view! method is called, a new id value for the view is formed by combining the question id with the IP address. The datastore is searched for an instance of ViewsCount containing the newly formed id value as its id. If no record is found, a new instance of ViewsCount containing this id as its id is saved to the database and the views_count variable of the Question is incremented by 1. If a record is found matching the id formed by the question id and IP address, then no action is taken ensuring unique counts are stored. However, ViewCounts more than a week old may be deleted in which case two views of a question made in two different weeks may be counted as two rather than one.
Link: https://github.com/ricodigo/shapado/blob/master/app/models/question.rb
Source:
  def viewed!(ip)
    view_count_id = "#{self.id}-#{ip}"
    if ViewsCount.where({:_id => view_count_id}).first.nil?
      ViewsCount.create(:_id => view_count_id)
      self.inc(:views_count, 1)
    end
  end

An example implementation

This view count feature is used in as implementation of Shapado I was involved in.
Link: https://github.com/b-change/satudunia/blob/master/app/views/questions/_question.html.haml Source:
%li.action
  = link_to t(question.views_count.to_s + ' views')

Class ViewsCount


Link: https://github.com/ricodigo/shapado/blob/master/app/models/views_count.rb

Source:
class ViewsCount
  include Mongoid::Document
  include Mongoid::Timestamps

  identity :type => String

  def self.cleanup!
    ViewsCount.delete_all(:created_at.lt => 8.days.ago)
  end
end

A Ruby class representing a MongoDB document. Each instance stands for a view of a question page from a particular IP address. The id is composed of the id of the web page and the IP address of the viewer.

 Contains a class method deleting all ViewsCount instances more than 8 days old.