跳至內容 跳至搜尋

Active Storage

Active Storage 讓上傳和參考雲端服務中的檔案變得簡單,例如 Amazon S3Google Cloud StorageMicrosoft Azure Storage,並將這些檔案附加到 Active Records。支援擁有主要服務和鏡像在其他服務中以利備援。它也提供磁碟服務以進行測試或本地部署,但重點在於雲端儲存。

檔案可以從伺服器上傳到雲端或直接從用戶端上傳到雲端。

此外,影像檔案可以使用依需求變體進行轉換,以調整品質、長寬比、大小或任何其他 MiniMagickVips 支援的轉換。

您可以在 Active Storage 概觀 指南中閱讀更多關於 Active Storage 的資訊。

與其他儲存解決方案比較

與 Rails 中其他附加檔案解決方案相比,Active Storage 運作方式的一個主要差異是透過使用內建 BlobAttachment 模型(由 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_pathrails_storage_proxy_url 形式的 URL 輔助工具。

<%= image_tag rails_storage_proxy_path(@user.avatar) %>

直接上傳

Active Storage 搭配其包含的 JavaScript 函式庫,支援從客戶端直接上傳到雲端。

直接上傳安裝

  1. 將 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()
    
  2. 使用直接上傳 URL 標記檔案輸入。

    <%= form.file_field :attachments, multiple: true, direct_upload: true %>
    
  3. 這樣就完成了!上傳會在提交表單時開始。

直接上傳 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 郵件清單中討論