Search code examples
ruby-on-railsrails-activestorage

ActiveStorage: checking if .attached? for a collection that has attachments preloaded (while avoiding n+1 queries of attached? method)


In my Rails 5 application, building a JSON API & using Activestorage for my attachments:

To avoid accessing an attachment that doesn't exist, I am using this if condition as shown in this answer but unfortunately this if condition makes a SQL query to check if the attachment is available or not, causing n+1 queries although I have already included (pre-loaded) the attachments for the records I have

How to check if the attachment exist on a record without hitting the DB, if I have preloaded the attachments already?

I tried to use .nil? but that will give a false positive that there is attachment even if there isn't (as shown below)

ActionView::Template::Error (to_model delegated to attachment, but attachment is nil):
  if !product.logo.nil?
    json.logo_img url_for(product.logo)

.attached? check works but causes the n+1 queries:

  if product.logo.attached?
    json.logo_img url_for(product.logo)

So while the below code looks very ugly, it works, preloading the attachments for all the records at once, but when checking if an attachment exists => this leads to n+1 queries

json.array!(@some_records.includes(integrated_product: [company: [ logo_attachment: :blob ]])) do |one_record|
  product ||= one_record.integrated_product
  if !product.logo.attached?
    json.logo_img url_for(product.logo)
  elsif !product.company.logo.attached?
    json.logo_img url_for(product.company.logo)
  end

....

Any thoughts on how to handle this in a proper way (preloading attachments & avoiding n+1) are appreciated.

Update:

I want to have the whole collection that I passed, including items with & without attachment, searching for a condition that will check if that already loaded item has an attachment or not to display an image if it has attachment


Solution

  • The problem turned out to be that the complex includes I had was not actually preloading the attachments (it was preloading for the nested record but not the main one), therefore the .attached? method was making a SQL query to check.

    However, when the correct preloading is done, the .attached? works correctly, checking the in-memory object without firing a seperate SQL query to check again

    I am leaving the question for the reference of the community if someone face a similar issue.