Active Storage
Active Storage 使得在云服务(如 Amazon S3、Google Cloud Storage 或 Microsoft Azure Storage)中上传和引用文件以及将这些文件附加到 Active Records 变得简单。支持使用一个主服务和在其他服务中镜像以实现冗余。它还提供了一个磁盘服务用于测试或本地部署,但重点是云存储。
文件可以从服务器上传到云,也可以直接从客户端上传到云。
此外,图像文件可以使用按需变体进行转换,以实现质量、纵横比、大小或任何其他 MiniMagick 或 Vips 支持的转换。
您可以在 Active Storage 概述 指南中了解更多关于 Active Storage 的信息。
与其他存储解决方案相比
Active Storage 与 Rails 中其他附件解决方案相比,一个关键区别在于它使用内置的 Blob 和 Attachment 模型(由 Active Record 支持)。这意味着现有的应用程序模型不需要修改额外的列来关联文件。Active Storage 使用多态关联通过 Attachment
连接模型,然后连接到实际的 Blob
。
Blob
模型存储附件元数据(文件名、内容类型等)以及它们在存储服务中的标识符键。 Blob
模型不存储实际的二进制数据。它们旨在保持不变。一个文件,一个 blob。您也可以将同一个 blob 与多个应用程序模型关联。如果您想对给定的 Blob
进行转换,想法是您只需创建一个新的,而不是尝试修改现有的(当然,如果您不需要,您可以稍后删除以前的版本)。
安装
运行 bin/rails active_storage:install
以复制 active_storage 迁移。
注意:如果找不到任务,请验证 config/application.rb
中是否存在 require "active_storage/engine"
。
示例
一个附件
class User < ApplicationRecord
# Associates an attachment and a blob. When the user is destroyed they are
# purged by default (models destroyed, and resource files deleted).
has_one_attached :avatar
end
# Attach an avatar to the user.
user.avatar.attach(io: File.open("/path/to/face.jpg"), filename: "face.jpg", content_type: "image/jpeg")
# Does the user have an avatar?
user.avatar.attached? # => true
# Synchronously destroy the avatar and actual resource files.
user.avatar.purge
# Destroy the associated models and actual resource files async, via Active Job.
user.avatar.purge_later
# Does the user have an avatar?
user.avatar.attached? # => false
# Generate a permanent URL for the blob that points to the application.
# Upon access, a redirect to the actual service endpoint is returned.
# This indirection decouples the public URL from the actual one, and
# allows for example mirroring attachments in different services for
# high-availability. The redirection has an HTTP expiration of 5 min.
url_for(user.avatar)
class AvatarsController < ApplicationController
def update
# params[:avatar] contains an ActionDispatch::Http::UploadedFile object
Current.user.avatar.attach(params.require(:avatar))
redirect_to Current.user
end
end
多个附件
class Message < ApplicationRecord
has_many_attached :images
end
<%= form_with model: @message, local: true do |form| %>
<%= form.text_field :title, placeholder: "Title" %><br>
<%= form.text_area :content %><br><br>
<%= form.file_field :images, multiple: true %><br>
<%= form.submit %>
<% end %>
class MessagesController < ApplicationController
def index
# Use the built-in with_attached_images scope to avoid N+1
@messages = Message.all.with_attached_images
end
def create
message = Message.create! params.require(:message).permit(:title, :content, images: [])
redirect_to message
end
def show
@message = Message.find(params[:id])
end
end
Variation
图像附件
<%# Hitting the variant URL will lazy transform the original blob and then redirect to its new service location %>
<%= image_tag user.avatar.variant(resize_to_limit: [100, 100]) %>
File
服务策略
Active Storage 支持两种服务文件的方式:重定向和代理。
重定向
Active Storage 为文件生成稳定的应用程序 URL,当访问这些 URL 时,会重定向到签名的、短暂的服务 URL。这减轻了应用程序服务器服务文件数据的负担。这是默认的文件服务策略。
当应用程序配置为默认代理文件时,请使用 rails_storage_redirect_path
和 _url
路由助手来重定向。
<%= image_tag rails_storage_redirect_path(@user.avatar) %>
代理
可以选择代理文件。这意味着您的应用程序服务器将从存储服务下载文件数据以响应请求。这对于从 CDN 服务文件很有用。
您可以将 Active Storage 配置为默认使用代理
# config/initializers/active_storage.rb
Rails.application.config.active_storage.resolve_model_to_route = :rails_storage_proxy
或者,如果您想显式代理特定附件,您可以使用 rails_storage_proxy_path
和 rails_storage_proxy_url
形式的 URL 助手。
<%= image_tag rails_storage_proxy_path(@user.avatar) %>
直接上传
Active Storage 及其包含的 JavaScript 库支持直接从客户端上传到云。
直接上传安装
-
将 Active Storage JavaScript 包含在您的应用程序的 JavaScript 包中,或直接引用它。
在应用程序 HTML 中,通过资产管道直接引用,不进行捆绑,并使用自动启动
<%= javascript_include_tag "activestorage" %>
在应用程序 HTML 中,通过 importmap-rails 引用,不进行捆绑,并使用自动启动,作为 ESM
# config/importmap.rb pin "@rails/activestorage", to: "activestorage.esm.js"
<script type="module-shim"> import * as ActiveStorage from "@rails/activestorage" ActiveStorage.start() </script>
使用资产管道
//= require activestorage
使用 npm 包
import * as ActiveStorage from "@rails/activestorage" ActiveStorage.start()
-
使用直接上传 URL 注释文件输入。
<%= form.file_field :attachments, multiple: true, direct_upload: true %>
-
就是这样!上传将在表单提交时开始。
直接上传 JavaScript 事件
事件名称 | 事件目标 | 事件数据(‘event.detail`) | 描述 |
---|---|---|---|
‘direct-uploads:start` | ‘<form>` | 无 | 提交了包含用于直接上传字段的文件的表单。 |
‘direct-upload:initialize` | ‘<input>` | ‘{id, file}` | 在表单提交后,为每个文件分派。 |
‘direct-upload:start` | ‘<input>` | ‘{id, file}` | 直接上传正在开始。 |
‘direct-upload:before-blob-request` | ‘<input>` | ‘{id, file, xhr}` | 在向您的应用程序发出直接上传元数据的请求之前。 |
‘direct-upload:before-storage-request` | ‘<input>` | ‘{id, file, xhr}` | 在发出存储文件的请求之前。 |
‘direct-upload:progress` | ‘<input>` | ‘{id, file, progress}` | 随着存储文件的请求的进行。 |
‘direct-upload:error` | ‘<input>` | ‘{id, file, error}` | 发生错误。除非此事件被取消,否则将显示 ‘alert`。 |
‘direct-upload:end` | ‘<input>` | ‘{id, file}` | 直接上传已结束。 |
‘direct-uploads:end` | ‘<form>` | 无 | 所有直接上传都已结束。 |
许可证
Active Storage 在 MIT 许可证 下发布。
支持
API 文档位于
Ruby on Rails 项目的错误报告可以在这里提交
功能请求应在以下位置的 rails-core 邮件列表中进行讨论
- MODULE ActiveStorage::Blobs
- MODULE ActiveStorage::DisableSession
- MODULE ActiveStorage::Reflection
- MODULE ActiveStorage::Representations
- 模块 ActiveStorage::SetCurrent
- 模块 ActiveStorage::Streaming
- 模块 ActiveStorage::Transformers
- 模块 ActiveStorage::VERSION
- 类 ActiveStorage::AnalyzeJob
- 类 ActiveStorage::Analyzer
- 类 ActiveStorage::Attached
- 类 ActiveStorage::Attachment
- 类 ActiveStorage::BaseController
- 类 ActiveStorage::BaseJob
- 类 ActiveStorage::Blob
- 类 ActiveStorage::DirectUploadsController
- 类 ActiveStorage::DiskController
- 类 ActiveStorage::Error
- 类 ActiveStorage::FileNotFoundError
- 类 ActiveStorage::Filename
- 类 ActiveStorage::FixtureSet
- 类 ActiveStorage::IntegrityError
- 类 ActiveStorage::InvariableError
- 类 ActiveStorage::LogSubscriber
- 类 ActiveStorage::MirrorJob
- 类 ActiveStorage::Preview
- 类 ActiveStorage::PreviewError
- 类 ActiveStorage::Previewer
- 类 ActiveStorage::PurgeJob
- 类 ActiveStorage::Service
- 类 ActiveStorage::TransformJob
- 类 ActiveStorage::UnpreviewableError
- 类 ActiveStorage::UnrepresentableError
- 类 ActiveStorage::Variant
- 类 ActiveStorage::VariantRecord
- 类 ActiveStorage::VariantWithRecord
- 类 ActiveStorage::Variation
- G
- R
- S
- V
类公共方法
gem_version() 链接
返回当前加载的 Active Storage 版本,以 Gem::Version
格式。
源代码: 显示 | 在 GitHub 上查看
# File activestorage/lib/active_storage/gem_version.rb, line 5 def self.gem_version Gem::Version.new VERSION::STRING end
replace_on_assign_to_many() 链接
源代码: 显示 | 在 GitHub 上查看
# File activestorage/lib/active_storage.rb, line 367 def self.replace_on_assign_to_many ActiveStorage.deprecator.warn("config.active_storage.replace_on_assign_to_many is deprecated and has no effect.") end
replace_on_assign_to_many=(value) 链接
源代码: 显示 | 在 GitHub 上查看
# File activestorage/lib/active_storage.rb, line 371 def self.replace_on_assign_to_many=(value) ActiveStorage.deprecator.warn("config.active_storage.replace_on_assign_to_many is deprecated and has no effect.") end
silence_invalid_content_types_warning() 链接
源代码: 显示 | 在 GitHub 上查看
# File activestorage/lib/active_storage.rb, line 375 def self.silence_invalid_content_types_warning ActiveStorage.deprecator.warn("config.active_storage.silence_invalid_content_types_warning is deprecated and has no effect.") end
silence_invalid_content_types_warning=(value) 链接
源代码: 显示 | 在 GitHub 上查看
# File activestorage/lib/active_storage.rb, line 379 def self.silence_invalid_content_types_warning=(value) ActiveStorage.deprecator.warn("config.active_storage.silence_invalid_content_types_warning is deprecated and has no effect.") end
version() 链接
返回当前加载的 Active Storage 版本,以 Gem::Version
格式。
源代码: 显示 | 在 GitHub 上查看
# File activestorage/lib/active_storage/version.rb, line 7 def self.version gem_version end