instance method
has_one_attached
Ruby on Rails edge
Since v6.0.6.1Signature
has_one_attached(name, dependent: :purge_later, service: nil, strict_loading: false, analyze: nil)
Specifies the relation between a single attachment and the model.
class User < ApplicationRecord
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.
Under the covers, this relationship is implemented as a has_one association to an ActiveStorage::Attachment record and a has_one-through association to an 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.
Instead, has_one_attached generates an ActiveStorage::Attached::One proxy to provide access to the associations and factory methods, like attach:
user.avatar.attach(uploaded_file)
The :dependent option defaults to :purge_later. This means the attachment 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 User < ActiveRecord::Base
has_one_attached :avatar, service: :s3
end
:service can also be specified as a proc, and it will be called with the model instance:
class User < ActiveRecord::Base
has_one_attached :avatar, service: ->(user) { user.in_europe_region? ? :s3_europe : :s3_usa }
end
To avoid N+1 queries, you can include the attached blobs in your query like so:
User.with_attached_avatar
If you need to enable strict_loading to prevent lazy loading of attachment, pass the :strict_loading option. You can do:
class User < ApplicationRecord
has_one_attached :avatar, strict_loading: true
end
Pass the analyze: option to control when analysis is performed:
class User < ApplicationRecord
has_one_attached :avatar, analyze: :immediately
end
Valid values are:
-
:immediately- Analyze before validation, making metadata available for validations -
:later(default) - Analyze in a background job after attachment -
:lazily- Skip automatic analysis; analyze on-demand when metadata is accessed
The default can be changed globally with config.active_storage.analyze = :immediately.
Note: Active Storage relies on polymorphic associations, which in turn store class names in the database. When renaming classes that use has_one_attached, make sure to also update the class names in the active_storage_attachments.record_type polymorphic type column of the corresponding rows.
Parameters
-
namereq -
dependentkey = :purge_later -
servicekey = nil -
strict_loadingkey = false -
analyzekey = nil
Source
# File activestorage/lib/active_storage/attached/model.rb, line 121
def has_one_attached(name, dependent: :purge_later, service: nil, strict_loading: false, analyze: nil)
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::One.new("#{name}", self)
end
def #{name}=(attachable)
attachment_changes["#{name}"] =
if attachable.nil? || attachable == ""
ActiveStorage::Attached::Changes::DeleteOne.new("#{name}", self)
else
ActiveStorage::Attached::Changes::CreateOne.new("#{name}", self, attachable)
end
end
CODE
has_one :"#{name}_attachment", -> { where(name: name) }, class_name: "ActiveStorage::Attachment", as: :record, inverse_of: :record, dependent: :destroy, strict_loading: strict_loading
has_one :"#{name}_blob", through: :"#{name}_attachment", class_name: "ActiveStorage::Blob", source: :blob, strict_loading: strict_loading
scope :"with_attached_#{name}", -> {
if ActiveStorage.track_variants
includes("#{name}_attachment": { blob: {
variant_records: { image_attachment: :blob },
preview_image_attachment: { blob: { variant_records: { image_attachment: :blob } } }
} })
else
includes("#{name}_attachment": :blob)
end
}
before_validation { attachment_changes[name.to_s]&.analyze }
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_one_attached,
name,
nil,
{ dependent: dependent, service_name: service, analyze: analyze },
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 121
· View on GitHub
· Improve this page
· Find usages on GitHub
Defined in ActiveStorage::Attached::Model