[Rails] Active Storage Overview
keywords:active storage, 檔案上傳, 雲端儲存
- Active Storage 概要 @ Calvert's murmur
- Using Active Storage @ Andyyou devBlog
- Active Storage Overview @ RailsGuides
安裝
# 建立專案後
$ rails new <project_name> --webpack=stimulus --database=postgresql --skip-coffee --skip-test
$ rails active_storage:install
$ rails db:migrate
設定
設定 Active Storage 的服務
# ./config/storage.yml
local:
service: Disk
root: <%= Rails.root.join("storage") %>
test:
service: Disk
root: <%= Rails.root.join("tmp/storage") %>
amazon:
service: S3
access_key_id: ''
secret_access_key: ''
根據不同開發環境設定不同的儲存位置:
# ./config/environments/development.rb
# Store files locally.
config.active_storage.service = :local
# ./config/environments/production.rb
# Store files on Amazon S3.
config.active_storage.service = :amazon
上傳檔案
has_one_attached
has_one_attached 用來將資料和檔案做一對一的關聯,每一筆資料可以有一個檔案。
假設我們有一個 Model 是 User :
# app/model/user.rb
class User < ApplicationRecord
has_one_attached :avatar
end
在資料庫不需要為 User 建立
:avatar欄位即可使用has_one_attached。
接著在 Controller 的部分把 :avatar 設定成可以使用的 params:
# app/controller/users_controller.rb
class UsersController < ApplicationController
#...
private
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:name, :avatar)
end
end
在 View 的地方使用 file_field 上傳圖檔,如此 Active Storage 會自動儲存上傳的檔案:
<%= form_with(model: user, local: true) do |form| %>
<!-- has_one_attached -->
<div class="field">
<%= form.label :avatar %>
<%= form.file_field :avatar %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
其他可用方法:avatar.attach, avatar.attached?
# 為使用者添加檔案
user.avatar.attach(params[:avatar])
# 檢查使用者是否有上傳檔案
user.avatar.attached?
❗ 透過
has_one_attached上傳時,如果同樣欄位有新的檔案上傳,則會把舊的檔案刪掉,儲存新的檔案。
has_many_attached
透過 has_many_attached 可以用來設定資料和檔案間的一對多關係,每一筆資料可以附帶很多的檔案:
# app/model/user.rb
class User < ApplicationRecord
has_one_attached :avatar
has_many_attached :images
end
接著在 Controller 的部分把 :images 設定成可以使用的 params:
# app/controller/users_controller.rb
class UsersController < ApplicationController
#...
private
# Never trust parameters from the scary internet, only allow the white list through.
def user_params
params.require(:user).permit(:name, :avatar, images: [])
end
end
在 View 的地方使用 file_field 搭配 multiple: true 上傳圖檔,如此 Active Storage 會自動儲存上傳的檔案:
<%= form_with(model: user, local: true) do |form| %>
<!-- has_many_attached -->
<div class="field">
<%= form.label :images %>
<%= form.file_field :images, multiple: true %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
其他可用方法:images.attach, images.attached?
user.images.attach(params[:images])
# 檢驗 user 有無任何 images
user.images.attached?
❗️ 透過
has_many_attached上傳時,如果同樣欄位有新的檔案上傳,則會保留舊的檔案,並把新的檔案附加上去。