Search code examples
ruby-on-railsactiverecordruby-on-rails-6rails-activestorage

How to query for records where Active Storage attached and image is variable?


How can I query for all the users who have an image attached and where the image is .variable??

e.g

I can do this

# controller

@users = User.all

view:


<% if user.image.attached? && user.image.variable? %>
<!-- display image -->
<% end %> 

Rather than having that logic in the view, I wonder if I can simply query for only those @users which meet the conditions of both user.image.attached? and user.image.variable?

Is this possible with some Active Record query?


Solution

  • Active Storage doesn't provide shortcut scopes for what you want, but you can come up with a custom solution.

    For fetching only users with an attached image, join the corresponding attachments:

    User.joins(:image_attachment)
    

    An attachment (or rather: a blob) is variable, if its content_type is present in the ActiveStorage.variable_content_types array, see https://github.com/rails/rails/blob/v6.1.3.2/activestorage/app/models/active_storage/blob/representable.rb#L42-L44.

    So we can further query for that content_type, but we need to join the blob (implicitly through the attachment) for that:

    User.joins(:image_blob).where(active_storage_blobs: {content_type: ActiveStorage.variable_content_types})
    

    And that should be the query for what you want. Additionally, you can have that as a scope so it's shorter when used:

    # app/models/user.rb
    
    scope :with_variable_image -> do
      joins(:image_blob).where(active_storage_blobs: {content_type: ActiveStorage.variable_content_types})
    end
    
    # app/controllers/users_controller.rb or wherever
    
    users = User.with_variable_image