instance method has_many_attached

Ruby on Rails 8.1.2

Since v6.0.6

Available in: v6.0.6 v6.1.7.10 v7.0.10 v7.1.6 v7.2.3 v8.0.4 v8.1.2

Signature

has_many_attached(name, dependent: :purge_later, service: nil, strict_loading: false)

Specifies the relation between multiple attachments and the model.

class Gallery < ApplicationRecord
  has_many_attached :photos
end

There are no columns defined on the model side, Active Storage takes care of the mapping between your records and the attachments.

Under the covers, this relationship is implemented as a has_many association to an ActiveStorage::Attachment record and a has_many-through association to an ActiveStorage::Blob record. These associations are available as photos_attachments and photos_blobs. But you shouldn’t need to work with these associations directly in most circumstances.

Instead, has_many_attached generates an ActiveStorage::Attached::Many proxy to provide access to the associations and factory methods, like attach:

user.photos.attach(uploaded_file)

The :dependent option defaults to :purge_later. This means the attachments will be purged (i.e. destroyed) in the background whenever the record is destroyed. If an ActiveJob::Backend queue adapter is not set in the application set it to purge instead.

If you need the attachment to use a service which differs from the globally configured one, pass the :service option. For example:

class Gallery < ActiveRecord::Base
  has_many_attached :photos, service: :s3
end

:service can also be specified as a proc, and it will be called with the model instance:

class Gallery < ActiveRecord::Base
  has_many_attached :photos, service: ->(gallery) { gallery.personal? ? :personal_s3 : :s3 }
end

To avoid N+1 queries, you can include the attached blobs in your query like so:

Gallery.where(user: Current.user).with_attached_photos

If you need to enable strict_loading to prevent lazy loading of attachments, pass the :strict_loading option. You can do:

class Gallery < ApplicationRecord
  has_many_attached :photos, strict_loading: true
end

Note: Active Storage relies on polymorphic associations, which in turn store class names in the database. When renaming classes that use has_many, make sure to also update the class names in the active_storage_attachments.record_type polymorphic type column of the corresponding rows.

Parameters

name req
dependent key = :purge_later
service key = nil
strict_loading key = false
Source
# File activestorage/lib/active_storage/attached/model.rb, line 210
      def has_many_attached(name, dependent: :purge_later, service: nil, strict_loading: false)
        Attached::Model.validate_service_configuration(service, self, name) unless service.is_a?(Proc)

        generated_association_methods.class_eval <<-CODE, __FILE__, __LINE__ + 1
          # frozen_string_literal: true
          def #{name}
            @active_storage_attached ||= {}
            @active_storage_attached[:#{name}] ||= ActiveStorage::Attached::Many.new("#{name}", self)
          end

          def #{name}=(attachables)
            attachables = Array(attachables).compact_blank
            pending_uploads = attachment_changes["#{name}"].try(:pending_uploads)

            attachment_changes["#{name}"] = if attachables.none?
              ActiveStorage::Attached::Changes::DeleteMany.new("#{name}", self)
            else
              ActiveStorage::Attached::Changes::CreateMany.new("#{name}", self, attachables, pending_uploads: pending_uploads)
            end
          end
        CODE

        has_many :"#{name}_attachments", -> { where(name: name) }, as: :record, class_name: "ActiveStorage::Attachment", inverse_of: :record, dependent: :destroy, strict_loading: strict_loading
        has_many :"#{name}_blobs", through: :"#{name}_attachments", class_name: "ActiveStorage::Blob", source: :blob, strict_loading: strict_loading

        scope :"with_attached_#{name}", -> {
          if ActiveStorage.track_variants
            includes("#{name}_attachments": { blob: {
              variant_records: { image_attachment: :blob },
              preview_image_attachment: { blob: { variant_records: { image_attachment: :blob } } }
            } })
          else
            includes("#{name}_attachments": :blob)
          end
        }

        after_save { attachment_changes[name.to_s]&.save }

        after_commit(on: %i[ create update ]) { attachment_changes.delete(name.to_s).try(:upload) }

        reflection = ActiveRecord::Reflection.create(
          :has_many_attached,
          name,
          nil,
          { dependent: dependent, service_name: service },
          self
        )
        yield reflection if block_given?
        ActiveRecord::Reflection.add_attachment_reflection(self, name, reflection)
      end

Defined in activestorage/lib/active_storage/attached/model.rb line 210 · View on GitHub · Improve this page · Find usages on GitHub

Defined in ActiveStorage::Attached::Model

Type at least 2 characters to search.

↑↓ navigate · open · esc close