Given a model with ActiveStorage
class User
has_one_attached :avatar
end
I can check whether a single user has an avatar
Attachment associations are named using the following convention:
<NAME OF ATTACHMENT>_attachment
For example, if you have has_one_attached :avatar
then the association name will be avatar_attachment
.
Now that you know how attachment associations are named, you can query them by using joins
as you would any other Active Record association.
For example, given the User
class below
class User
has_one_attached :avatar
end
You can query for all User
records that have that attachment as follows
User.joins(:avatar_attachment)
This performs an INNER JOIN
which will only return records which have the attachment.
You can query for all User
records that DO NOT have that attachment like this
User.
left_joins(:avatar_attachment).
group(:id).
having("COUNT(active_storage_attachments) = 0")
Slightly related, here is how to perform a search query on the attached records:
def self.search_name(search)
with_attached_attachment.
references(:attachment_attachment).
where(ActiveStorage::Blob.arel_table[:filename].matches("%#{search}%"))
end
You'll just have to update the with_attached_attachment
and :attachment_attachment
to reflect your attached model. In my case I have has_one_attached :attachment
And for those wondering, the Arel #matches
does not appear to be susceptible to SQL injection attacks.
I wanted to know if a record has any attachments (I had multiple attachments say a passport and other docs for User
) so I can display/hide a section in UI.
Based on the answer here I've been able to add the following method to ApplicationRecord
:
def any_attached?
ActiveStorage::Attachment.where(record_type: model_name.to_s, record_id: id).any?
end
Then you can use it like:
User.last.any_attached?
#=> true