Calvert's murmur

在 Heroku 使用 Active Storage

2018-05-22

約 5302 字 / 需 29 分鐘閱讀

原文:HEROKU BLOGRails 5.2 Active Storage: Previews, Poppler, and Solving Licensing Pitfalls

上個月剛剛發佈的 Rails 5.2 有一個重要的新功能:Active Storage。Active Storage 支援各種後端服務(如 AWS S3),為 Active Record 模型提供檔案上傳和附件功能。雖然有像 Paperclip 這樣的函式庫來做類似的工作,但這是 Rails 第一次發佈這樣的功能。在 Heroku,我們認為雲端儲存是最佳實作規範,所以我們確保它能在我們的平台上執行。在這篇文章中,我們將分享如何準備發佈 Rails 5.2,以及如何在部署的應用程式中使用新的 Active Storage 功能。

信任但要驗證

在 Heroku,信任是我們的第一價值。當我們得知 Active Storage 隨著 Rails 5.2 發佈時,我們開始嘗試使用它的所有功能。Active Storage 其中一個最便利的功能就是能夠預覽 PDF 和影片。PDF 或影片的小截圖將從檔案中擷取並呈現在頁面上,而不是透過文字連結到資源。

測試版的 Rails 5.2 使用了熱門的開源工具 FFmpeg 和 MuPDF 來產生影片和 PDF 預覽。透過我們的安全及法務部門審查了這些新的二進位相依檔案,我們發現 MuPDF 採用 AGPL 授權條款,並且需要商業許可才能使用。如果我們在預設情況下簡單地將 MuPDF 加到 Rails 5.2+ 的應用程式中,我們的許多客戶會不知道他們需要購買 MuPDF 才能在商業上使用它。

AGPL 授權條款的限制在 2017 年 9 月引起公眾關注。為了準備 5.2 版本,我們的工程師 Terence Lee 致力於更新 Active Storage,以便 PDF 預覽功能也可以使用沒有商業許可的開源後端程式。我們在 2018 年 2 月向 Rails 提交了一個 PR,介紹採用 poppler PDF 作為 MuPDF 的替代方案的能力。該 PR 大約在 1 個月後被合併,現在任何 Rails 5.2 使用者,無論是否在 Heroku,都無需購買商業許可即可呈現 PDF 預覽。

展示在 Heroku 使用 Active Storage

如果你已經有實作 Active Storage 的應用程式,則可以跳轉到我們開發中心的 Active Storage 文件

或者,你可以使用我們的應用程式範例。這是一個 Rails 5.2 應用程式,它是數位布告欄,允許使用者張貼影片、PDF 和圖片。你可以在 Github 檢視原始碼或用 Heroku 按鈕部署應用程式:

注意:這個應用程式範例需要付費的 S3 附加元件。

以下是該應用程式的範例影片。

當你開啟首頁時,選擇適當的資源檔,然後送出表單。在影片中,mp4 檔案被上傳到 S3,然後透過 ffmpeg 幫助 Rails 產生預覽。很簡約。

在 Heroku 使用 Active Storage

如果你使用按鈕部署應用程式範例,它已經透過 app.json 設定能在 Heroku 上運作,但是,如果你有自己的應用程式想要部署,你要如何設定它以便在 Heroku 上運作?

根據開發中心的 Active Storage 文件,你將需要一個檔案儲存服務,讓你所有的 dynos 都可以與其溝通。該範例使用名為 Bucketeer 的 Heroku S3 附加元件,但你也可以使用現有的 S3 憑證。

馬上開始,請將 S3 的 AWS gem 加到 Gemfile,如果你要修改圖片,請加入 Mini Magick:

gem "aws-sdk-s3", require: false
gem 'mini_magick', '~> 4.8'

更新 Gemfile 後別忘了 $ bundle install

接下來,在你的 config/storage.yml 檔案中加入一個 amazon 選項來指向 S3 設定,在這個範例中我們使用了由 Bucketeer 設定的配置:

amazon:
  service: S3
  access_key_id: <%= ENV['BUCKETEER_AWS_ACCESS_KEY_ID'] %>
  secret_access_key: <%= ENV['BUCKETEER_AWS_SECRET_ACCESS_KEY'] %>
  region: <%= ENV['BUCKETEER_AWS_REGION'] %>
  bucket: <%= ENV['BUCKETEER_BUCKET_NAME'] %>

然後確保你的應用程式設定為在生產環境中使用 :amazon 儲存配置:

config.active_storage.service = :amazon

如果你忘記了這一步,預設的儲存是使用 :local 將檔案儲存到磁碟。這不是處理生產環境中上傳檔案的可擴展方式。如果你不小心將它部署到 Heroku,首先它會顯示檔案已上傳,但是如果你執行超過一個 dyno,他們會在隨機的請求中消失。當重新啟動 dynos 時,這些檔案將完全消失。你可以在開發中心取得有關 Heroku 的臨時磁碟的更多資訊。

最後,要使其在生產環境中運作的最後一件事是安裝一個客制的建置套件,它將安裝用來產生資源預覽的二進位相依檔案 ffmpegpoppler

$ heroku buildpacks:add -i 1 https://github.com/heroku/heroku-buildpack-activestorage-preview

一但你完成了,就可以部署到 Heroku!

將 Active Storage 加到現有應用程式

如果你的應用程式還沒有 Active Storage,可以把它加入。首先,你需要執行以下指令啟用 Active Storage:

$ bin/rails active_storage:install

這會新增一個遷移,讓 Rails 追蹤上傳的檔案。

接下來,你需要一個模型來「附加」檔案。你可以使用現有模型或建立新模型。在應用程式範例中,使用了幾乎是空的 bulletin 模型:

$ bin/rails generate scaffold bulletin

接下來,在應用程式上執行遷移:

$ bin/rails db:migrate

在資料庫遷移後,更新模型讓 Rails 知道你打算讓它能夠附加檔案:

class Bulletin < ApplicationRecord
  has_one_attached :attachment
end

一旦完成,我們還需要三個部分:上傳附件的表單、儲存附件的控制器以及呈現附件的視圖。

如果你有一個現有的表單,你可以透過 file_field 視圖輔助方法加入一個附件欄位:

<%= form.file_field :attachment %>

你可以在應用程式範例中看到帶有附件的表單範例。一旦有了表單,你將需要保存附件。

在這個應用程式範例中,首頁包含了表單和視圖。附件在 bulletin 控制器被儲存,然後將使用者導回主布告列表:

def create
  @bulletin = Bulletin.new()
  @bulletin.attachment.attach(params[:bulletin][:attachment])
  @bulletin.save!

  redirect_back(fallback_location: root_path)
end

最後,在 welcome 視圖中,我們迭代每個布告項目,並根據我們的附件類型,以不同的方式呈現。

在 Active Storage 中,對於 PDF 和影片,只要系統安裝了正確的二進位檔案,previewable? 方法將回傳 true。對於圖片,如果安裝了 mini_magickvariable? 方法將回傳 true。如果這些都不是 true,那麼附件可能是一個最好在下載後查看的檔案。下面展示了我們如何表示該邏輯

<ul class="no-bullet">
  <% @bulletin_list.each do |bulletin| %>
    <li>
      <% if bulletin.attachment.previewable? %>
        <%= link_to(image_tag(bulletin.attachment.preview(resize: "200x200>")),  rails_blob_path(bulletin.attachment, disposition: "attachment"))
        %>
      <% elsif bulletin.attachment.variable? %>
        <%= link_to(image_tag(bulletin.attachment.variant(resize: "200x200")), rails_blob_path(bulletin.attachment, disposition: "attachment"))%>
      <% else %>
        <%= link_to "Download file", rails_blob_path(bulletin.attachment, disposition: "attachment") %>
      <% end %>
    </li>
  <% end %>
</ul>

一旦你完成以上所有步驟,並將 Active Storage 設定為在生產環境中運作,使用者就可以輕鬆上傳和下載檔案。