2014-08-04 04:07:55 -05:00
|
|
|
require 'ipaddr'
|
|
|
|
|
|
|
|
# awkward TopicView is taken
|
|
|
|
class TopicViewItem < ActiveRecord::Base
|
|
|
|
self.table_name = 'topic_views'
|
|
|
|
belongs_to :user
|
|
|
|
validates_presence_of :topic_id, :ip_address, :viewed_at
|
|
|
|
|
2014-08-05 01:14:10 -05:00
|
|
|
def self.add(topic_id, ip, user_id=nil, at=nil, skip_redis=false)
|
2014-08-04 04:07:55 -05:00
|
|
|
# Only store a view once per day per thing per user per ip
|
|
|
|
redis_key = "view:#{topic_id}:#{Date.today.to_s}"
|
|
|
|
if user_id
|
|
|
|
redis_key << ":user-#{user_id}"
|
|
|
|
else
|
|
|
|
redis_key << ":ip-#{ip}"
|
|
|
|
end
|
|
|
|
|
2014-08-05 01:14:10 -05:00
|
|
|
if skip_redis || $redis.setnx(redis_key, "1")
|
|
|
|
skip_redis || $redis.expire(redis_key, 1.day.to_i)
|
2014-08-04 04:07:55 -05:00
|
|
|
|
|
|
|
TopicViewItem.transaction do
|
|
|
|
at ||= Date.today
|
2014-08-05 01:14:10 -05:00
|
|
|
|
|
|
|
# AR likes logging failures here, we don't need that
|
2014-08-04 04:07:55 -05:00
|
|
|
TopicViewItem.create!(topic_id: topic_id, ip_address: ip, viewed_at: at, user_id: user_id)
|
|
|
|
|
|
|
|
# Update the views count in the parent, if it exists.
|
|
|
|
Topic.where(id: topic_id).update_all 'views = views + 1'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
rescue ActiveRecord::RecordNotUnique
|
|
|
|
# don't care, skip
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
# == Schema Information
|
|
|
|
#
|
|
|
|
# Table name: topic_views
|
|
|
|
#
|
|
|
|
# topic_id :integer not null
|
|
|
|
# viewed_at :date not null
|
|
|
|
# user_id :integer
|
|
|
|
# ip_address :inet not null
|
|
|
|
#
|
|
|
|
# Indexes
|
|
|
|
#
|
|
|
|
# index_topic_views_on_topic_id_and_viewed_at (topic_id,viewed_at)
|
|
|
|
# index_topic_views_on_viewed_at_and_topic_id (viewed_at,topic_id)
|
|
|
|
# ip_address_topic_id_topic_views (ip_address,topic_id) UNIQUE
|
|
|
|
# user_id_topic_id_topic_views (user_id,topic_id) UNIQUE
|
|
|
|
#
|