Active Storage Blob
Blob 是一个记录,包含有关文件的元数据以及该文件在服务中的存储位置的键。Blob 可以通过两种方式创建
-
在文件上传到服务端之前,使用
create_and_upload!
。此操作需要服务器上提供包含文件内容的可重绕io
。 -
在文件直接上传到服务端之前,使用
create_before_direct_upload!
。
第一个选项不需要任何客户端 JavaScript 集成,并且可以被处理文件的任何其他后端服务使用。第二个选项更快,因为您没有将自己的服务器用作上传的暂存点,并且可以与 Heroku 等不提供大量磁盘空间的部署一起使用。
Blob 在其对特定文件的引用方面被认为是不可变的。您可以在后续传递中更新 Blob 的元数据,但您不应更新键或更改已上传的文件。如果您需要创建派生文件或以其他方式更改 Blob,只需创建一个新的 Blob 并清除旧的 Blob 即可。
- 模块 ActiveStorage::Blob::Analyzable
- 模块 ActiveStorage::Blob::Identifiable
- 模块 ActiveStorage::Blob::Representable
- A
- C
- D
- F
- G
- I
- K
- O
- P
- S
- T
- U
- V
- ActiveStorage::Blob::Analyzable
- ActiveStorage::Blob::Identifiable
- ActiveStorage::Blob::Representable
常量
MINIMUM_TOKEN_LENGTH | = | 28 |
类公共方法
compose(blobs, key: nil, filename:, content_type: nil, metadata: nil) 链接
将多个 Blob 合并为一个“组合”Blob。
源代码:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 144 def compose(blobs, key: nil, filename:, content_type: nil, metadata: nil) raise ActiveRecord::RecordNotSaved, "All blobs must be persisted." if blobs.any?(&:new_record?) content_type ||= blobs.pluck(:content_type).compact.first new(key: key, filename: filename, content_type: content_type, metadata: metadata, byte_size: blobs.sum(&:byte_size)).tap do |combined_blob| combined_blob.compose(blobs.pluck(:key)) combined_blob.save! end end
create_and_upload!(key: nil, io:, filename:, content_type: nil, metadata: nil, service_name: nil, identify: true, record: nil) 链接
创建一个新的 Blob 实例,然后将给定 io
的内容上传到服务。Blob 实例将在上传开始之前被保存,以防止上传由于键冲突而覆盖其他 Blob。提供内容类型时,传递 identify: false
以绕过自动内容类型推断。
源代码:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 95 def create_and_upload!(key: nil, io:, filename:, content_type: nil, metadata: nil, service_name: nil, identify: true, record: nil) create_after_unfurling!(key: key, io: io, filename: filename, content_type: content_type, metadata: metadata, service_name: service_name, identify: identify).tap do |blob| blob.upload_without_unfurling(io) end end
create_before_direct_upload!(key: nil, filename:, byte_size:, checksum:, content_type: nil, metadata: nil, service_name: nil, record: nil) 链接
返回一个保存的 Blob,不将文件上传到服务。此 Blob 将指向一个还没有文件的键。它旨在与客户端上传一起使用,客户端上传将首先创建 Blob 以生成用于上传的签名 URL。此签名 URL 指向 Blob 生成的键。提交使用直接上传的表单后,可以使用签名 ID 将 Blob 与正确的记录关联起来。
源代码:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 106 def create_before_direct_upload!(key: nil, filename:, byte_size:, checksum:, content_type: nil, metadata: nil, service_name: nil, record: nil) create! key: key, filename: filename, byte_size: byte_size, checksum: checksum, content_type: content_type, metadata: metadata, service_name: service_name end
find_signed(id, record: nil, purpose: :blob_id) 链接
您可以使用 Blob 的签名 ID 在客户端上引用它,而无需担心篡改。这对于直接上传特别有用,在直接上传中,客户端需要在表单提交时引用在上传之前创建的 Blob 本身。
签名 ID 还用于通过 BlobsController 为 Blob 创建稳定 URL。
源代码:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 69 def find_signed(id, record: nil, purpose: :blob_id) super(id, purpose: purpose) end
find_signed!(id, record: nil, purpose: :blob_id) 链接
与 find_signed
的工作方式相同,但如果 signed_id
已过期、目的不匹配或被篡改,则会引发 ActiveSupport::MessageVerifier::InvalidSignature
异常。如果有效的签名 ID 找不到记录,它还会引发 ActiveRecord::RecordNotFound
异常。
源代码:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 76 def find_signed!(id, record: nil, purpose: :blob_id) super(id, purpose: purpose) end
generate_unique_secure_token(length: MINIMUM_TOKEN_LENGTH) 链接
为了防止在不区分大小写的文件系统中出现问题,特别是在与将索引视为区分大小写的数据库结合使用时,生成的 Blob 键将只包含 36 进制字符字母表,因此将为小写。为了保持与 has_secure_token
使用的 58 进制编码相同或更高的熵量,使用的字节数从标准的 24 字节增加到 28 字节
源代码:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 115 def generate_unique_secure_token(length: MINIMUM_TOKEN_LENGTH) SecureRandom.base36(length) end
unattached 链接
返回没有附加到任何记录的 Blob。
源代码:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 38 scope :unattached, -> { where.missing(:attachments) }
实例公共方法
attachments 链接
返回关联的 ActiveStorage::Attachment
实例。
源代码:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 32 has_many :attachments
audio?() 链接
如果此 Blob 的 content_type 在音频范围内(如 audio/mpeg),则返回 true。
源代码:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 212 def audio? content_type.start_with?("audio") end
custom_metadata() 链接
源代码:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 198 def custom_metadata self[:metadata][:custom] || {} end
custom_metadata=(metadata) 链接
源代码:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 202 def custom_metadata=(metadata) self[:metadata] = self[:metadata].merge(custom: metadata) end
delete() 链接
删除与 Blob 关联的服务上的文件。只有在 Blob 也要删除时才应这样做,否则您将实际上有一个失效的引用。在大多数情况下,建议使用 purge
和 purge_later
方法。
源代码:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 322 def delete service.delete(key) service.delete_prefixed("variants/#{key}/") if image? end
download(&block) 链接
下载与此 Blob 关联的文件。如果没有给出块,则将整个文件读入内存并返回。对于非常大的文件,这将使用大量 RAM。如果给出块,则下载将以块的形式进行流式传输并生成。
源代码:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 282 def download(&block) service.download key, &block end
download_chunk(range) 链接
下载与此 Blob 关联的文件的一部分。
源代码:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 287 def download_chunk(range) service.download_chunk key, range end
filename() 链接
返回一个 ActiveStorage::Filename
实例,该实例表示可以查询其基名、扩展名以及文件名安全版本的名称,该文件名可在 URL 中安全使用。
源代码:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 194 def filename ActiveStorage::Filename.new(self[:filename]) end
image?() 链接
如果此 Blob 的 content_type 在图像范围内(如 image/png),则返回 true。
源代码:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 207 def image? content_type.start_with?("image") end
key() 链接
返回指向与此 Blob 关联的服务上文件的键。该键为 Rails 中的安全性令牌格式,为小写。因此它将类似于:xtapjjcjiudrlk3tmwyjgpuobabd。此键不打算直接向用户公开。始终使用 signed_id
或经过验证的键形式引用 Blob。
源代码:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 186 def key # We can't wait until the record is first saved to have a key for it self[:key] ||= self.class.generate_unique_secure_token(length: MINIMUM_TOKEN_LENGTH) end
open(tmpdir: nil, &block) 链接
将 Blob 下载到磁盘上的临时文件。生成临时文件。
临时文件的名称以 ActiveStorage-
和 Blob 的 ID 为前缀。它的扩展名与 Blob 的扩展名匹配。
默认情况下,临时文件是在 Dir.tmpdir
中创建的。传递 tmpdir:
以在其他目录中创建它
blob.open(tmpdir: "/path/to/tmp") do |file|
# ...
end
在执行给定块后,临时文件会自动关闭并解除链接。
如果下载的数据与 Blob 的校验和不匹配,则会引发 ActiveStorage::IntegrityError
。
来源:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 304 def open(tmpdir: nil, &block) service.open( key, checksum: checksum, verify: !composed, name: [ "ActiveStorage-#{id}-", filename.extension_with_delimiter ], tmpdir: tmpdir, &block ) end
purge() 链接
销毁 blob 记录并从服务中删除文件。这是处理不需要的 blob 的推荐方法。但请注意,从服务中删除文件将启动与服务的 HTTP 连接,这可能会很慢或被阻止,因此您不应该在事务或回调中使用此方法。请改用 purge_later
。
来源:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 330 def purge destroy delete if previously_persisted? rescue ActiveRecord::InvalidForeignKey end
purge_later() 链接
将一个 ActiveStorage::PurgeJob
排队以调用 purge
。这是从事务、Active Record 回调或任何其他实时场景中清除 blob 的推荐方法。
来源:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 338 def purge_later ActiveStorage::PurgeJob.perform_later(self) end
service() 链接
返回服务实例,该实例可以在全局或每个附件级别进行配置
来源:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 343 def service services.fetch(service_name) end
service_headers_for_direct_upload() 链接
返回一个用于 service_url_for_direct_upload
请求的 Hash
头部。
来源:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 242 def service_headers_for_direct_upload service.headers_for_direct_upload key, filename: filename, content_type: content_type, content_length: byte_size, checksum: checksum, custom_metadata: custom_metadata end
service_url_for_direct_upload(expires_in: ActiveStorage.service_urls_expire_in) 链接
返回一个 URL,该 URL 可用于直接将文件上传到此 blob 在服务上的位置。此 URL 旨在为了安全起见而短暂存在,并且仅由负责上传的客户端 JavaScript 按需生成。
来源:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 237 def service_url_for_direct_upload(expires_in: ActiveStorage.service_urls_expire_in) service.url_for_direct_upload key, expires_in: expires_in, content_type: content_type, content_length: byte_size, checksum: checksum, custom_metadata: custom_metadata end
signed_id(purpose: :blob_id, expires_in: nil, expires_at: nil) 链接
返回此 blob 的签名 ID,该 ID 适用于在客户端进行引用,无需担心篡改。
来源:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 178 def signed_id(purpose: :blob_id, expires_in: nil, expires_at: nil) super end
text?() 链接
如果此 blob 的 content_type 属于文本范围(如 text/plain),则返回 true。
来源:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 222 def text? content_type.start_with?("text") end
upload(io, identify: true) 链接
将 io
上传到此 blob 的 key
上的服务。Blob 旨在不可变,因此在文件已上传到 blob 后,您不应该使用此方法。如果您想创建一个派生 blob,您应该简单地创建一个基于旧 blob 的新 blob。
在上传之前,我们会计算校验和,校验和将发送到服务以进行传输完整性验证。如果校验和与服务接收到的校验和不匹配,则会引发异常。我们还会测量 io
的大小,并将该大小存储在 blob 记录上的 byte_size
中。内容类型会自动从 io
中提取,除非您指定 content_type
并将 identify
传递为 false。
通常,您根本不需要直接调用此方法。请改用 create_and_upload!
类方法。如果您确实直接使用此方法,请确保您是在持久化的 Blob
上使用它,否则另一个 blob 的数据可能会在服务上被覆盖。
来源:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 259 def upload(io, identify: true) unfurl io, identify: identify upload_without_unfurling io end
url(expires_in: ActiveStorage.service_urls_expire_in, disposition: :inline, filename: nil, **options) 链接
返回 blob 在服务上的 URL。这将为公共文件返回永久 URL,并为私有文件返回短暂 URL。私有文件已签名,不供公开使用。相反,URL 应该仅作为来自稳定 URL(可能是经过身份验证的)的重定向来公开。将 URL 隐藏在重定向后面还可以让您在不更新所有 URL 的情况下更改服务。
来源:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 230 def url(expires_in: ActiveStorage.service_urls_expire_in, disposition: :inline, filename: nil, **options) service.url key, expires_in: expires_in, filename: ActiveStorage::Filename.wrap(filename || self.filename), content_type: content_type_for_serving, disposition: forced_disposition_for_serving || disposition, **options end
video?() 链接
如果此 blob 的 content_type 属于视频范围(如 video/mp4),则返回 true。
来源:显示 | 在 GitHub 上
# File activestorage/app/models/active_storage/blob.rb, line 217 def video? content_type.start_with?("video") end