Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

counter_cache in Rails on a scoped association

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?

like image 833
GMA Avatar asked May 04 '16 13:05

GMA


Video Answer


1 Answers

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.

like image 194
Dave Powers Avatar answered Sep 16 '22 13:09

Dave Powers