Module: ActiveStorage::Attached::Macros

Defined in:
lib/active_storage/attached/macros.rb

Overview

Provides the class-level DSL for declaring that an Active Record model has attached blobs.

Instance Method Summary collapse

Instance Method Details

#has_many_attached(name, dependent: :purge_later) ⇒ Object

Specifies the relation between multiple attachments and the model.

class Gallery < ActiveRecord::Base
  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.

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

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

Under the covers, this relationship is implemented as a has_many association to a ActiveStorage::Attachment record and a has_many-through association to a 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.

The system has been designed to having you go through the ActiveStorage::Attached::Many proxy that provides the dynamic proxy to the associations and factory methods, like #attach.

If the :dependent option isn't set, all the attachments will be purged (i.e. destroyed) whenever the record is destroyed.



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/active_storage/attached/macros.rb', line 77

def has_many_attached(name, dependent: :purge_later)
  class_eval <<-CODE, __FILE__, __LINE__ + 1
    def #{name}
      @active_storage_attached_#{name} ||= ActiveStorage::Attached::Many.new("#{name}", self, dependent: #{dependent == :purge_later ? ":purge_later" : "false"})
    end

    def #{name}=(attachables)
      #{name}.attach(attachables)
    end
  CODE

  has_many :"#{name}_attachments", -> { where(name: name) }, as: :record, class_name: "ActiveStorage::Attachment", inverse_of: :record, dependent: false do
    def purge
      each(&:purge)
      reset
    end

    def purge_later
      each(&:purge_later)
      reset
    end
  end
  has_many :"#{name}_blobs", through: :"#{name}_attachments", class_name: "ActiveStorage::Blob", source: :blob

  scope :"with_attached_#{name}", -> { includes("#{name}_attachments": :blob) }

  if dependent == :purge_later
    after_destroy_commit { public_send(name).purge_later }
  else
    before_destroy { public_send(name).detach }
  end
end

#has_one_attached(name, dependent: :purge_later) ⇒ Object

Specifies the relation between a single attachment and the model.

class User < ActiveRecord::Base
  has_one_attached :avatar
end

There is no column defined on the model side, Active Storage takes care of the mapping between your records and the attachment.

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

User.with_attached_avatar

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

The system has been designed to having you go through the ActiveStorage::Attached::One proxy that provides the dynamic proxy to the associations and factory methods, like attach.

If the :dependent option isn't set, the attachment will be purged (i.e. destroyed) whenever the record is destroyed.



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/active_storage/attached/macros.rb', line 30

def has_one_attached(name, dependent: :purge_later)
  class_eval <<-CODE, __FILE__, __LINE__ + 1
    def #{name}
      @active_storage_attached_#{name} ||= ActiveStorage::Attached::One.new("#{name}", self, dependent: #{dependent == :purge_later ? ":purge_later" : "false"})
    end

    def #{name}=(attachable)
      #{name}.attach(attachable)
    end
  CODE

  has_one :"#{name}_attachment", -> { where(name: name) }, class_name: "ActiveStorage::Attachment", as: :record, inverse_of: :record, dependent: false
  has_one :"#{name}_blob", through: :"#{name}_attachment", class_name: "ActiveStorage::Blob", source: :blob

  scope :"with_attached_#{name}", -> { includes("#{name}_attachment": :blob) }

  if dependent == :purge_later
    after_destroy_commit { public_send(name).purge_later }
  else
    before_destroy { public_send(name).detach }
  end
end