I have User model which has_many :notifications. Notification has a boolean column seen and a scope called :unseen which returns all notifications where seen is false.

class User < ApplicationRecord
  has_many :notifications
  has_many :unseen_notifications, -> { unseen }, class_name: "Notification"

I know that I can cache the number of notifications if I add a column called notifications_count to users and add counter_cache: true to my belongs_to call in Notification.

But what if I want to cache the number of unseen notifications a user has? I.e. cache unseen_notifications.size instead of notifications.size? Is there a built-in way to do this with counter_cache or do I have to roll my own solution?

  • 1
    As far as I know, there is no built-in way to do this. But you can try counter_culture gem. It might fit your needs
    – Van Huy
    May 4 '16 at 14:29

According to this blog post, there is no built-in way to use counter caches for scoped associations:

ActiveRecord’s counter cache callbacks only fire when creating or destroying records, so adding a counter cache on a scoped association won’t work. For advanced cases, like only counting the number of published responses, check out the counter_culture gem.

Other than using an external gem, you could roll your own solution by adding callbacks to your Notification model and adding an integer column (e.g., unseen_notifications_count) to the User model:

# Notification.rb
after_save    :update_counter_cache
after_destroy :update_counter_cache

def update_counter_cache
  self.user.unseen_notifications_count = self.user.unseen_notifications.size

Also see the answers to Counter Cache for a column with conditions? for additional implementation examples of this approach.

Your Answer

