Reputation: 1348
I searched for this and was surprised not to find an answer, so I might be overcomplicating this. But, basically I have a couple of RESTful models in my Rails 3 application that I would like to keep track of, in a pretty simple way, just for popularity tracking over time. In my case, I'm only interested in tracking hits on the GET/show method–Users log in and view these two resources, their number of visits go up with each viewing/page load.
So, I have placed a "visits" column on the Books model:
== AddVisitsToBooks: migrating ===============================================
-- add_column(:books, :visits, :integer)
-> 0.0008s
== AddVisitsToBooks: migrated (0.0009s) ======================================
The column initializes to zero, then, basically, inside the books_controller,
def show
unless @book.owner == current_user #hypothetically, we won't let an owner
"cheat" their way to being popular
@book.visits = @book.visits + 1
@book.save
end
And this works fine, except now every time a show method is being called, you've got not only a read action for the object record, but a write, as well. And perhaps that gets to the heart of my question; is the total overhead required just to insert the single integer change a big deal in a small-to-midsize production app? Or is it a small deal, or basically nothing at all?
Is there a much smarter way to do it? Everything else I came up with still involved writing to a record every time the given page is viewed. Would indexing the field help, even if I'm rarely searching by it?
The database is PostgreSQL 9, by the way (running on Heroku).
Thanks!
Upvotes: 2
Views: 426
Reputation: 1348
After some more searching, I decided to take the visits counter off of the models themselves, because as MiGro said, it would be blocking the row every time the page is shown, even if just for a moment. I think the DB sequence approach is probably the fastest, and I am going to research it more, but for the moment it is a bit beyond me, and seems a bit cumbersome to implement in ActiveRecord. Thus,
https://github.com/charlotte-ruby/impressionist
seems like a decent alternative; keeping the view counts in an alternate table and utilizing a gem with a blacklist of over 1200 robots, etc, etc.
Upvotes: 2
Reputation: 1511
What you described above has one significant cons: once the process updates database (increase visit counter) the row is blocked and if there is any other process it has to wait.. I would suggest using DB Sequence for this reason: http://www.postgresql.org/docs/8.1/static/sql-createsequence.html However you need to maintain the sequence custom in your code: Ruby on Rails+PostgreSQL: usage of custom sequences
Upvotes: 4