How to implement a viewing system in Rails

Hello everyone.

Today I will show how to implement a viewing system for any model of your Rails application.

Suppose we have a model News and we would like to keep track of how many times a single news has been displayed, in order to implement box like “the most ‘seen’” etc..

Suppose we have a model News created in this way:

myapp/db/migrate/001_create_news.rb:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class CreateNews < ActiveRecord::Migration
  def self.up
    create_table :news do |t|
      t.string  :title
      t.text    :content
      t.date    :online_date_start, :null => true
      t.date    :online_date_end,   :null => true
      t.boolean :online,            :null => false, :default => true
      t.timestamps
    end
  end

  def self.down
    drop_table :news
  end
end

myapp/app/models/news.rb:

1
2
3
4
class News < ActiveRecord::Base
  validates_length_of :title, :within => 2..255
  validates_presence_of :title, :content, :online_date_start
end

The basic idea is to increment a counter displayed every time a user views the news.

Some considerations:

an implementation of this type would allow a user to press the refresh button and constantly increase the counter.

So the goal is to have a clever mechanism that increases the counter:

  • 1 once for each registered user

  • 1 only once per IP in the case of guest

We would also like that this mechanism could be applied not only to model News, but to any model of our application.

Then we create the migration of our model Viewing:

myapp/db/migrate/002_create_viewings.rb:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class CreateViewings < ActiveRecord::Migration
  def self.up
    create_table   :viewings do |t|
      t.string     :ip
      t.string     :viewable_type
      t.integer    :viewable_id
      t.references :person
      t.datetime   :created_at
    end
  end

  def self.down
    drop_table :viewings
  end
end

and the corresponding model:

myapp/app/models/viewing.rb:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Viewing < ActiveRecord::Base
  # RELATIONSHIPS
  belongs_to :viewable, :polymorphic => true, :counter_cache => :popularity
  belongs_to :viewer, :class_name => "Person", :foreign_key => "person_id"

  # VALIDATIONS
  validates_uniqueness_of :ip, :scope => [:viewable_id, :viewable_type, :person_id]
  validates_uniqueness_of :person_id, :allow_nil => true

  # OTHER
  def viewable_type=(sType)
    super(sType.to_s.classify.constantize.base_class.to_s)
  end
end

As you can see, the model Viewing is not closely tied to model News, but given its polimorphic nature, it may be associated with any model.

At this point, we can associate the model Viewing to the News :

myapp/app/models/news.rb:

1
2
3
4
5
class News < ActiveRecord::Base
  validates_length_of :title, :within => 2..255
  validates_presence_of :title, :content, :online_date_start
  has_many :viewings, :as => :viewable
end

and add the column “counter cache to the table News:

myapp/db/migrate/003_add_popularity_to_news.rb:

1
Specified file is not in uploads folder, does not exists, or not a file.

Now we have everything necessary to implement the mechanism for viewing in our model News.

Let’s show how to increment the counter to “show” of the news.

myapp/app/controllers/news_controller.rb:

1
Specified file is not in uploads folder, does not exists, or not a file.


Tags: ,


About Stefano

Stefano Mancini is a co-founder of DevInterface.

After graduating in Computer Science, he first specialized in Java/J2EE development by participating in several international projects in the pharmaceutical and banking ambits.

Enthusiast of agile development, like SCRUM for project management and eXtreme Programming for code writing, he then moved to dynamic languages like Ruby and Python.

About DevInterface

We are an information and communication technology agency. Our mission is to provide web application development, design services and communication strategies. We specialize in building web applications with modern and efficient frameworks.

Related Post

3 Responses to “How to implement a viewing system in Rails”

  1. Social comments and analytics for this post…

    This post was mentioned on Twitter by devinterface: New blog post, “How to implement a viewing system in Rails” – http://tr.im/D1n4...

Leave a Reply

Insert code beetween <code lang="ruby"> and </code>

Copyright 2012 DevInterface s.n.c.

DevInterface Blog is proudly powered by WordPress