No release in over 3 years
Low commit activity in last 3 years
Custom counter_cache functionality that supports conditions and multiple models.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

>= 1.3.3, < 1.4.0

Runtime

>= 4.0
 Project Readme

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

Custom Counter Cache¶ ↑

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

Installation¶ ↑

Add the following to your Gemfile:

gem 'custom_counter_cache'

Example¶ ↑

Class with 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

Class with callbacks¶ ↑

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.

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 }