counter_cache in Rails on a scoped association
Asked Answered
D

1

12

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"
end

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?

Donatello answered 4/5, 2016 at 13:52 Comment(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 needsSurgy
S
7

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
  self.user.save
end

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

Solarism answered 19/12, 2019 at 19:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.