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
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.