Rails Counter Cache with Active Storage

577 views Asked by At

I have a Account model with 3 attachments, using Active Storage, has_many_attached :attachments.

I want to know how many attached files the account has, the most efficient way (aka no joins)

The only solution I found is Account.last.attachments.count or .size, but it makes two query: one for the account and one using active_storage_attachments table.

Is there a way to counter cache the number of attachments?

Thank you in advance

EDIT

Of course I can set up my own database field and count it, I want to know if there is some default

EDIT

I tried to do has_many_attached :attachments, counter_cache: true, but it gives an error

2

There are 2 answers

0
msuliq On BEST ANSWER

I had similar issue with a model that had 7 file attachments, which I needed to count using counter cache instead of the a database query. The trick is that you have to specify counter cache reference in the child model, which has the belongs_to :ParentModel - ActiveStorage::Attachment in my case. ActiveStorage::Attachment is a 'behind-the-scenes' model of Rails so I monkey patched it. But instead of implementing counter cache by adding counter_cache: :true I decided to implement it through callbacks. I created a module for the ParentModel with following structure:

module ParentModel::ModuleName
  extend ActiveSupport::Concern

  class ActiveStorage::Attachment
    require 'active_record/counter_cache'

    before_create :after_create_action, if: :record_parent_model?
    before_destroy :after_destroy_action, if: :record_parent_model?

    def after_create_action
      ParentModel.increment_counter(:attachments_count, record_id, touch: true)
    end

    def after_destroy_action
      ParentModel.decrement_counter(:attachments_count, record_id, touch: true)
    end

    def record_parent_model?
      record_type == 'ParentModel'
    end
  end
end

And I created a migration to add :attachments_count column to the ParentModel as in case of a straight forward counter cache implementation.

3
Ben On