aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/active_storage/attached.rb2
-rw-r--r--lib/active_storage/attached/macros.rb18
-rw-r--r--lib/active_storage/attached/many.rb16
-rw-r--r--lib/active_storage/attached/one.rb11
-rw-r--r--lib/active_storage/service.rb12
-rw-r--r--lib/active_storage/service/disk_service.rb2
-rw-r--r--lib/active_storage/service/gcs_service.rb2
-rw-r--r--lib/active_storage/service/mirror_service.rb6
-rw-r--r--lib/active_storage/service/s3_service.rb2
9 files changed, 61 insertions, 10 deletions
diff --git a/lib/active_storage/attached.rb b/lib/active_storage/attached.rb
index 8bec129a1a..4644d74bcc 100644
--- a/lib/active_storage/attached.rb
+++ b/lib/active_storage/attached.rb
@@ -4,7 +4,7 @@ require "active_storage/attachment"
require "action_dispatch/http/upload"
require "active_support/core_ext/module/delegation"
-# Abstract baseclass for the particular `ActiveStorage::Attached::One` and `ActiveStorage::Attached::Many`
+# Abstract baseclass for the concrete `ActiveStorage::Attached::One` and `ActiveStorage::Attached::Many`
# classes that both provide proxy access to the blob association for a record.
class ActiveStorage::Attached
attr_reader :name, :record
diff --git a/lib/active_storage/attached/macros.rb b/lib/active_storage/attached/macros.rb
index 11f88f16e5..89297e5bdf 100644
--- a/lib/active_storage/attached/macros.rb
+++ b/lib/active_storage/attached/macros.rb
@@ -9,6 +9,15 @@ module ActiveStorage::Attached::Macros
# 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 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.
def has_one_attached(name, dependent: :purge_later)
@@ -38,6 +47,15 @@ module ActiveStorage::Attached::Macros
#
# 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.
def has_many_attached(name, dependent: :purge_later)
diff --git a/lib/active_storage/attached/many.rb b/lib/active_storage/attached/many.rb
index ea4aade5d7..035cd9c091 100644
--- a/lib/active_storage/attached/many.rb
+++ b/lib/active_storage/attached/many.rb
@@ -1,24 +1,28 @@
-# Representation of multiple attachments to a model.
+# Decorated proxy object representing of multiple attachments to a model.
class ActiveStorage::Attached::Many < ActiveStorage::Attached
delegate_missing_to :attachments
# Returns all the associated attachment records.
#
- # You don't have to call this method to access the attachments' methods as
- # they are all available at the model level.
+ # All methods called on this proxy object that aren't listed here will automatically be delegated to `attachments`.
def attachments
record.public_send("#{name}_attachments")
end
- # Associates one or several attachments with the current record, saving
- # them to the database.
+ # Associates one or several attachments with the current record, saving them to the database.
+ # Examples:
+ #
+ # document.images.attach(params[:images]) # Array of ActionDispatch::Http::UploadedFile objects
+ # document.images.attach(params[:signed_blob_id]) # Signed reference to blob from direct upload
+ # document.images.attach(io: File.open("~/racecar.jpg"), filename: "racecar.jpg", content_type: "image/jpg")
+ # document.images.attach([ first_blob, second_blob ])
def attach(*attachables)
attachables.flatten.collect do |attachable|
attachments.create!(name: name, blob: create_blob_from(attachable))
end
end
- # Checks the presence of attachments.
+ # Returns true if any attachments has been made.
#
# class Gallery < ActiveRecord::Base
# has_many_attached :photos
diff --git a/lib/active_storage/attached/one.rb b/lib/active_storage/attached/one.rb
index d255412842..0c522e856e 100644
--- a/lib/active_storage/attached/one.rb
+++ b/lib/active_storage/attached/one.rb
@@ -10,14 +10,19 @@ class ActiveStorage::Attached::One < ActiveStorage::Attached
record.public_send("#{name}_attachment")
end
- # Associates a given attachment with the current record, saving it to the
- # database.
+ # Associates a given attachment with the current record, saving it to the database.
+ # Examples:
+ #
+ # person.avatar.attach(params[:avatar]) # ActionDispatch::Http::UploadedFile object
+ # person.avatar.attach(params[:signed_blob_id]) # Signed reference to blob from direct upload
+ # person.avatar.attach(io: File.open("~/face.jpg"), filename: "face.jpg", content_type: "image/jpg")
+ # person.avatar.attach(avatar_blob) # ActiveStorage::Blob object
def attach(attachable)
write_attachment \
ActiveStorage::Attachment.create!(record: record, name: name, blob: create_blob_from(attachable))
end
- # Checks the presence of the attachment.
+ # Returns true if an attachment has been made.
#
# class User < ActiveRecord::Base
# has_one_attached :avatar
diff --git a/lib/active_storage/service.rb b/lib/active_storage/service.rb
index 127895406f..e6361318a8 100644
--- a/lib/active_storage/service.rb
+++ b/lib/active_storage/service.rb
@@ -58,26 +58,38 @@ class ActiveStorage::Service
end
end
+ # Upload the `io` to the `key` specified. If a `checksum` is provided, the service will
+ # ensure a match when the upload has completed or raise an `ActiveStorage::IntegrityError`.
def upload(key, io, checksum: nil)
raise NotImplementedError
end
+ # Return the content of the file at the `key`.
def download(key)
raise NotImplementedError
end
+ # Delete the file at the `key`.
def delete(key)
raise NotImplementedError
end
+ # Return true if a file exists at the `key`.
def exist?(key)
raise NotImplementedError
end
+ # Returns a signed, temporary URL for the file at the `key`. The URL will be valid for the amount
+ # of seconds specified in `expires_in`. You most also provide the `disposition` (`:inline` or `:attachment`),
+ # `filename`, and `content_type` that you wish the file to be served with on request.
def url(key, expires_in:, disposition:, filename:, content_type:)
raise NotImplementedError
end
+ # Returns a signed, temporary URL that a direct upload file can be PUT to on the `key`.
+ # The URL will be valid for the amount of seconds specified in `expires_in`.
+ # You most also provide the `content_type`, `content_length`, and `checksum` of the file
+ # that will be uploaded. All these attributes will be validated by the service upon upload.
def url_for_direct_upload(key, expires_in:, content_type:, content_length:, checksum:)
raise NotImplementedError
end
diff --git a/lib/active_storage/service/disk_service.rb b/lib/active_storage/service/disk_service.rb
index 3cde203a31..7e2079385f 100644
--- a/lib/active_storage/service/disk_service.rb
+++ b/lib/active_storage/service/disk_service.rb
@@ -3,6 +3,8 @@ require "pathname"
require "digest/md5"
require "active_support/core_ext/numeric/bytes"
+# Wraps a local disk path as a Active Storage service. See `ActiveStorage::Service` for the generic API
+# documentation that applies to all services.
class ActiveStorage::Service::DiskService < ActiveStorage::Service
attr_reader :root
diff --git a/lib/active_storage/service/gcs_service.rb b/lib/active_storage/service/gcs_service.rb
index 4632e5f820..d681a3dc45 100644
--- a/lib/active_storage/service/gcs_service.rb
+++ b/lib/active_storage/service/gcs_service.rb
@@ -1,6 +1,8 @@
require "google/cloud/storage"
require "active_support/core_ext/object/to_query"
+# Wraps the Google Cloud Storage as a Active Storage service. See `ActiveStorage::Service` for the generic API
+# documentation that applies to all services.
class ActiveStorage::Service::GCSService < ActiveStorage::Service
attr_reader :client, :bucket
diff --git a/lib/active_storage/service/mirror_service.rb b/lib/active_storage/service/mirror_service.rb
index 54465cad05..7c407f2730 100644
--- a/lib/active_storage/service/mirror_service.rb
+++ b/lib/active_storage/service/mirror_service.rb
@@ -1,5 +1,8 @@
require "active_support/core_ext/module/delegation"
+# Wraps a set of mirror services and provides a single `ActiveStorage::Service` object that will all
+# have the files uploaded to them. A `primary` service is designated to answer calls to `download`, `exists?`,
+# and `url`.
class ActiveStorage::Service::MirrorService < ActiveStorage::Service
attr_reader :primary, :mirrors
@@ -16,12 +19,15 @@ class ActiveStorage::Service::MirrorService < ActiveStorage::Service
@primary, @mirrors = primary, mirrors
end
+ # Upload the `io` to the `key` specified to all services. If a `checksum` is provided, all services will
+ # ensure a match when the upload has completed or raise an `ActiveStorage::IntegrityError`.
def upload(key, io, checksum: nil)
each_service.collect do |service|
service.upload key, io.tap(&:rewind), checksum: checksum
end
end
+ # Delete the file at the `key` on all services.
def delete(key)
perform_across_services :delete, key
end
diff --git a/lib/active_storage/service/s3_service.rb b/lib/active_storage/service/s3_service.rb
index 72ff9f3f36..c21977044d 100644
--- a/lib/active_storage/service/s3_service.rb
+++ b/lib/active_storage/service/s3_service.rb
@@ -1,6 +1,8 @@
require "aws-sdk"
require "active_support/core_ext/numeric/bytes"
+# Wraps the Amazon Simple Storage Service (S3) as a Active Storage service.
+# See `ActiveStorage::Service` for the generic API documentation that applies to all services.
class ActiveStorage::Service::S3Service < ActiveStorage::Service
attr_reader :client, :bucket, :upload_options