Search code examples
ruby-on-railsruby-on-rails-3counter-cache

Rails: best way to turn these requests into a counter_cache


I've got several of these requests each page load:

SELECT COUNT(*) FROM `impressions` WHERE `impressions`.`impressionable_id` IN (229) AND `impressions`.`impressionable_type` = 'Document' AND (YEAR(created_at) = 2013 && MONTH(created_at) = 8 && DAY(created_at) = 12)
SELECT COUNT(*) FROM `impressions` WHERE `impressions`.`impressionable_id` IN (229) AND `impressions`.`impressionable_type` = 'Document' AND (YEAR(created_at) = 2013 && MONTH(created_at) = 8 && DAY(created_at) = 13)
SELECT COUNT(*) FROM `impressions` WHERE `impressions`.`impressionable_id` IN (229) AND `impressions`.`impressionable_type` = 'Document' AND (YEAR(created_at) = 2013 && MONTH(created_at) = 8 && DAY(created_at) = 14)
SELECT COUNT(*) FROM `impressions` WHERE `impressions`.`impressionable_id` IN (229) AND `impressions`.`impressionable_type` = 'Document' AND (YEAR(created_at) = 2013 && MONTH(created_at) = 8 && DAY(created_at) = 15)

I'd like to reduce load on the server so I'm trying to turn it into a counter_cache solution. I need a bit of help designing it because of the complex relationship I'm trying to count. Here's the query that gets the counts:

Impression.where(:impressionable_id => component.publications.where(:document_id => document).first.id).count

Where should I put the counter_cache column? And how should I write the migration? Component and Document are in a has_many relationship through Publications.


Solution

  • Assuming impression counts are for Publication, and impression count is to be grouped by each day.

    You could create PublicationImpression model to serve as a counter for the impression of each Publication per day.

    class CreatePublicationImpressions < ActiveRecord::Migration
      def self.up
        create_table :publication_impressions, :id => false do |t|
          t.integer :impressions, :default => 0
          t.datetime :date
          t.references :publication
    
          t.timestamps
        end
      end
    
      def self.down
        drop_table :publication_impressions
      end
    end