Rails ActiveStorage scope for when file is attached
Asked Answered
Z

2

13

When using ActiveStorage, how do you create a scope for when files are attached.

For example:

class Check < ActiveRecord::Base
  has_one_attached :image
end

I want something like Check.has_attached_image to return only records where there is an existing attached image.

I know that ActiveStorage provides a with_attached_image scope. But that doesn't seem to be working:

irb(main):009:0> Check.with_attached_image.to_sql => "SELECT \"checks\".* FROM \"checks\""

Zerk answered 7/11, 2018 at 23:24 Comment(0)
P
21

Main purpose of the scope with_attached_image is to avoid N+1 queries (to include the attached blobs in your query).

To return only records where there is an existing attached image, you can create a scope in the Check model like this:

scope :has_attached_image, -> { joins(image_attachment: :blob) }

Update from comments:

scope :has_attached_image, -> { joins(:image_attachment) }

Paramagnetism answered 8/11, 2018 at 0:0 Comment(6)
This is closer (in that it gives fewer results), but it's still returning results where I do check.image.attached? and get false. It may be because an image was previously attached and now isn't? Though can't confirm that...just ideating.Zerk
@Zerk how do you delete image attachment? Do you use #purge method like this: check.image_attachment.purge ?Paramagnetism
Not sure what was happening, but now can't reproduce. Looks like this worked well. Thanks @Zoran Majstorovic!Zerk
I don't think you need the join on the blob as well, just the attachment.Headstream
@TomRossi is correct, joins(:image_attachment) is sufficient. It queries the active_storage_attachments table, which is a join table between the model's table & the active_storage_blobs table. Joining the blob table is redundant & just adds another table (and time) to the query.Nara
The answer is updated to reflect new findings, thanks to @TomRossiParamagnetism
H
2

This includes a scope for both when an attachment exists and when it doesn't exist:

class Check < ActiveRecord::Base
  has_one_attached :image

  scope :has_image, -> { joins(:image_attachment) }
  scope :missing_image, -> { where.missing(:image_attachment) }

end
Headstream answered 11/5, 2022 at 19:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.