iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 29
0
自我挑戰組

非本科之30天Ruby / Rails學習筆記系列 第 29

Day29: Rails - Active Storage

最近做專案遇到了上傳檔案的問題,想針對這個主題簡單的做個介紹。

Active Storage

Active Storage可以將文件上傳到Amazon S3,Google Cloud Storage或Microsoft Azure Storage等雲存儲服務,並將這些文件附加到Active Record。

它是一個可以用於開發或測試的服務,並可將文件進行備份和遷移。

其中,使用Active Storage,可以使用ImageMagick轉換圖像上傳,上傳非圖像或圖像(如PDF或影片)的檔案,並可任意從文件中存取。

by Rails Guide-Active Storage Overview

據 Rails 官方文件說明,Active Storage 是在 Rails 5.2版後才推出的功能,在它之前似乎多數人都使用 Paperclip 及 CarrierWave,這次將會已上傳圖片為例來做說明。

在開始之前,得先在終端機執行以下指令:

rails active_storage:install
rails db:migrate

第一行會產生兩個table的migration:

# This migration comes from active_storage (originally 20170806125915)
class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
  def change
    create_table :active_storage_blobs do |t|
      t.string   :key,        null: false
      t.string   :filename,   null: false
      t.string   :content_type
      t.text     :metadata
      t.bigint   :byte_size,  null: false
      t.string   :checksum,   null: false
      t.datetime :created_at, null: false

      t.index [ :key ], unique: true
    end

    create_table :active_storage_attachments do |t|
      t.string     :name,     null: false
      t.references :record,   null: false, polymorphic: true, index: false
      t.references :blob,     null: false

      t.datetime :created_at, null: false

      t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
      t.foreign_key :active_storage_blobs, column: :blob_id
    end
  end
end

db:migrate之後,就可以看到 schema.rb 已新增兩個 table:

active_storage_blobs: 存放附檔資訊
active_storage_attachments: 存放附檔和 model 的關聯

其中附加檔案的方式有分成一個 model 一個檔案或甚至多個檔案,我們先已有個food model舉例:

一個食物一個檔案

#food.rb
class Food < ApplicationRecord
  has_one_attached :avatar
end

其實在schema裡是看不到avatar這個欄位,可以想成是“虛擬欄位的概念”。

如果要做個可以上傳的表單的話,可以利用 form_for來實現:

#@foods = Food.all
<%= form_for(@foods) do |form| %>

  <%= form.label :avatar, '檔案上傳', 
  <%= form.file_field :avatar%>
#下略  
<% end %>

Strong parameter

只要是丟資料到網站上,都需要permit才可以,故要在params的地方也要記得要加上:avatar去permit。

  def clean_params
    params.require(:food).permit(:title, :address, :phone, :quantity, :origin_price, :discount_price, :pickup_time, :picture, :description, :endup_time, :avatar)
  end

要新增檔案可以用:

food.avatar.attach(params[:avatar])

若要確定是否有附加檔案的話,可以用:

food.avatar.attached?

# 回傳boolean值

一個食物多個檔案

差異其實只有兩個:

改成has_many_attached

#food.rb
class Food < ApplicationRecord
 #has_one_attached :avatar
  has_many_attached :avatars
end

改成陣列型式avatars:[]

  def clean_params
    params.require(:food).permit(:title, :address, :phone, :quantity, :origin_price, :discount_price, :pickup_time, :picture, :description, :endup_time, avatars:[])
  end

關於“新增檔案”及“確定是否有附加檔案”的方式是一樣的,只是記得avatar要用複數形式(avatars)

附加完檔案了,如果是照片的話要如何顯示呢?

mini_magick

在Rails的 Gemfile 其實有內建一個套件 mini_magick,若要做圖片顯示的效果,可以把註解拿掉 bundle 後就可以用了。

#Gemfile
# Use ActiveStorage variant
gem 'mini_magick', '~> 4.8'
<%= image_tag food.avatar.variant(resize: '300x300'), if food.avatar.attached?%>

variant方法是用來改變上傳的圖片尺寸
if food.avatar.attached? 有附加檔案的話就印出圖片。

如果沒有加上這個判斷的話,今天頁面的某個檔案若剛好沒有附加檔案,就會噴錯,原因是“food.avatarnil,不能對nilvariant方法”。

參考資料:

Rails Guides - Active Storage Overview
Active Storage 開箱文
[Rails] Active Storage Overview

“Don’t worry about failure; you only have to be right once.”

— Drew Houston, Entrepreneur

本文同步發佈於: https://louiswuyj.tw/


上一篇
Day28: 用個Github來版本控制吧
下一篇
Day30: 我竟然完賽了?
系列文
非本科之30天Ruby / Rails學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言