'How to determine active storage association?

I have one upload form for all models using active storage attachment(s). Functionality in this form can change depending on if the uploader is a has_one_attached or has_many_attached. Is there a rails way to determine which association type a given model has?



Solution 1:[1]

You can use reflect_on_all_associations:

https://api.rubyonrails.org/classes/ActiveRecord/Reflection/ClassMethods.html#method-i-reflect_on_all_associations

Account.reflect_on_all_associations   # returns an array of all associations
Account.reflect_on_all_associations(:has_many)  # returns an array of all has_many associations

I've not tried it but I'm assuming:

Model.reflect_on_all_associations(:has_one_attached)

Will contain a record if the model :has_one_attached, and be empty if it doesn't.

Solution 2:[2]

I don't love this approach, but it works. All my models have only one attachment association. If a model had more than one attachment association, this would break. I'll continue to fine tune this.

def can_have_many_attachments?
  uploader_name.present? &&
    uploader_name.ends_with?('s')
end

def uploader_name
  self.class.reflect_on_all_attachments.last.name.to_s
end

Solution 3:[3]

The following seems to work, at least for Active Storage.

ModelName.reflect_on_all_associations.select { |a|
  a.class_name == 'ActiveStorage::Attachment'
}

And if you want just the attribute names:

ModelName.reflect_on_all_associations.select { |a|
  a.class_name == 'ActiveStorage::Attachment'
}.map(&:name)

Solution 4:[4]

Yes, the following code determines if the attachment named manuscript on the Publication model is a has-many attachment

(Publication.reflect_on_attachment :manuscript).
    instance_of? ActiveStorage::Reflection::HasManyAttachedReflection

(note this is all a single statement continued on a second line)

Alternatively, you can do

(Publication.reflect_on_attachment :manuscript).macro == :has_many_attached

Replace many with one to test if it's a HasOneAttached.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Mark
Solution 2 hellion
Solution 3 Jason Swett
Solution 4 Peter Gerdes