Skip to content
This repository was archived by the owner on Nov 7, 2025. It is now read-only.

cedric/custom_counter_cache

Repository files navigation

<img src=“badge.fury.io/rb/custom_counter_cache.svg” alt=“Gem Version” /> <img src=“travis-ci.org/cedric/custom_counter_cache.svg?branch=master” alt=“Build Status” />

This is a simple approach to creating a custom counter cache in Rails that can be used across multiple models.

Add the following to your Gemfile:

gem 'custom_counter_cache'

This is the block that will be used to calculate the value for the counter cache. It will be called by other models through their association via an after_save or after_destroy callback.

include CustomCounterCache::Model
define_counter_cache :articles_count do |user|
  user.articles.where(state: 'published').count
end

This will define the after_create, after_update and after_destroy callbacks. An :if option can be provided to limit when these callbacks get triggered.

include CustomCounterCache::Model
update_counter_cache :user, :articles_count, if: -> (article) { article.state_changed? }

These callbacks can be added to any number of models that might need to change the counter cache.

To store the counter cache you need to create a column for the model with the counter cache (example: articles_count).

If you would like to store all of your counter caches in a single table, you can use this migration:

create_table :counters do |t|
  t.references :countable, polymorphic: true
  t.string :key, null: false
  t.integer :value, null: false, default: 0
  t.timestamps
end
add_index :counters, [ :countable_id, :countable_type, :key ], unique: true

Here is the example model to go with:

class Counter < ActiveRecord::Base
  belongs_to :countable, polymorphic: true
  validates :countable, presence: true
end

If you would like to store your counter cache in an existing table, you can use this migration:

def change
  add_column :users, :articles_count, :integer, default: 0, null: false
end

To backfill your counters, run something like this either in a migration or in the console:

User.select(:id).find_each(batch_size: 100) { |u| u.update_articles_count }

About

Custom counter_cache functionality that supports conditions and multiple models.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 13