Active Storage
Active Storage 讓上傳和參考雲端服務中的檔案變得簡單,例如 Amazon S3、Google Cloud Storage 或 Microsoft Azure Storage,並將這些檔案附加到 Active Records。支援擁有主要服務和鏡像在其他服務中以利備援。它也提供磁碟服務以進行測試或本地部署,但重點在於雲端儲存。
檔案可以從伺服器上傳到雲端或直接從用戶端上傳到雲端。
此外,影像檔案可以使用依需求變體進行轉換,以調整品質、長寬比、大小或任何其他 MiniMagick 或 Vips 支援的轉換。
您可以在 Active Storage 概觀 指南中閱讀更多關於 Active Storage 的資訊。
與其他儲存解決方案比較
與 Rails 中其他附加檔案解決方案相比,Active Storage 運作方式的一個主要差異是透過使用內建 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
影像附件的變異
<%# 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" %>
透過 importmap-rails 要求,不透過資產管線進行套件化,在應用程式 HTML 中不自動啟動,作為 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}` | 發生錯誤。除非取消此事件,否則會顯示「警示`」。 |
‘direct-upload:end` | ‘<input>` | ‘{id, file}` | 直接上傳已結束。 |
‘direct-uploads:end` | ‘<form>` | 無 | 所有直接上傳已結束。 |
授權
Active Storage 在 MIT 授權 下發布。
支援
API 文件位於
Ruby on Rails 專案的錯誤報告可以提交至
功能要求應在此處的 rails-core 郵件清單中討論