rails上傳圖片
功能製作教學
前情提要:
圖片上傳 + s3 的使用
安裝指令、一些插件
下面這個指令,會產生三個表單,一個是blobs、active_storage_attachments、active_storage_variant_records
$ bin/rails active_storage:install
-----
Copied migration 20230423073109_create_active_storage_tables.active_storage.rb from active_storage
-----
$ rails db:migrate
-----
== 20230423073109 CreateActiveStorageTables: migrating ========================
-- create_table(:active_storage_blobs, {:id=>:primary_key})
-> 0.0023s
-- create_table(:active_storage_attachments, {:id=>:primary_key})
-> 0.0010s
-- create_table(:active_storage_variant_records, {:id=>:primary_key})
-> 0.0007s
== 20230423073109 CreateActiveStorageTables: migrated (0.0040s) ===============
-----
三個table個代表的意思
-
active_storage_blobs表格存儲了所有的附件(blobs),包括圖像、影片、聲音等等。每個blob都是一個文件的數據,由一個key來唯一標識。該表格中的id列是主鍵,key列是唯一索引。
-
active_storage_attachments表格存儲了附件和模型之間的關係。 每個附件可以被多個模型所關聯,每個關聯都有一個附件ID和一個模型ID。該表格中的id列是主鍵,name列存儲了附件的名稱,record_type列存儲了模型的類別名稱,record_id列存儲了模型的ID,blob_id列存儲了附件的ID。
-
active_storage_variant_records表格存儲了所有的附件變體(variants),也就是對原始附件進行裁剪、縮放等操作後生成的新附件。每個變體對應一個原始附件和一組轉換參數,例如縮放大小、裁剪位置等等。該表格中的id列是主鍵,blob_id列存儲了原始附件的ID,variation_digest列存儲了轉換參數的摘要。
這些表格是Active Storage用於儲存附件的重要組成部分,它們提供了一個強大的API,讓我們可以輕鬆地在Rails應用程序中管理和處理各種類型的附件。
使用者加上大頭貼(單圖)
model部分
class User < ApplicationRecord
has_one_attached :avatar
# ... 省略
end
新增欄位部分,text_field 加上去
<!-- views/devise/registrations/new.html.erb -->
<h2>Sign up</h2>
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= render "devise/shared/error_messages", resource: resource %>
// ...省略
<div class="field">
<%= f.label :avatar %><br />
<%= f.file_field :avatar %>
</div>
// ...省略
<% end %>
圖片強參數
name這個強參數是之前新增的,這次新增的avatar,這樣新增後,才可以賞用者新增大頭貼
# app/controllers/users/registrations_controller.rb
def configure_sign_up_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :avatar])
end
頁面顯示
接著我們把來判斷,如果今天使用者提供圖片,我們就顯示在navbar上
> <nav>
> ...省略
>
> <li><%= image_tag current_user.avatar %></li>
>
> ...省略
> </nav>
不過這樣會遇到一個問題,就是圖片大小太大了,我們來把它縮小一點
限制大小
首先先下載一個外掛,這個插件可以幫我們控制圖片大小
$ bundle add image_processing
下載好後,在model地方這樣設定,這樣顯示的圖片就不會太大張
class User < ApplicationRecord
has_one_attached :avatar do |attachable|
# 依照實際大小
attachable.variant :thumb, resize_to_limit: [100, 100]
# 每張圖會依照比例縮放
attachable.variant :standard, resize_to_fill: [1200, 900]
end
# ...省略
end
圖片更新
如果今天沒有特別修改路徑的話,預設編輯資料的路徑應該是這樣
<!-- view/shared/_navbar.html.erb -->
> <nav>
> ...省略
>
> <li><%= link_to "更新暱稱", edit_user_registration_path(current_user.id), class:"mr-2 text-lg hover:text-major" %></li>
>
> ...省略
>
> </nav>
有了路徑,我們來增加edit頁面應該要多兩個欄位
<!-- views/devise/registrations/edit.html.erb -->
> <div>
> ...省略
>
> <div class="field">
> <%= f.label :name %><br />
> <%= f.text_field :name %>
> </div>
>
> <div class="field">
> <%= f.label :name %><br />
> <%= f.file_field :avatar %>
> </div>
>
> ...省略
> </div>
最後我們把強參數加上去,記得不論是新增使用者還是編輯使用者資料,都要記得有強參數這個東西喔!
# app/controllers/users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
before_action :configure_sign_up_params, only: [:create]
# 這個是編輯資料的強參數方法
before_action :configure_account_update_params, only: [:update]
# If you have extra params to permit, append them to the sanitizer.
def configure_account_update_params
devise_parameter_sanitizer.permit(:account_update, keys: [:name, :avatar])
end
end
加上圖片大小限制
為了避免使用者都上傳過大的圖片,所以我們幫圖片上傳加上一點限制
參考檔案 - https://github.com/igorkasyanchuk/active_storage_validations
安裝插件
$ bundle add active_storage_validations
model加上限制
class User < ApplicationRecord
has_one_attached :avatar do |attachable|
attachable.variant :thumb, resize_to_limit: [100, 100]
end
# 這一行,加上去後,使用者之後無法上傳超過 1MB 的圖片
validates :avatar, attached: true, size: {less_than: 1.megabytes, message: '不能超過1MB'}
# ...省略
end
房屋加上各式圖片(多圖)
model 設定
如果今天要設定一個房子可以有很多張圖片的話,這邊是這樣設定
class House < ApplicationRecord
has_many_attached :images
end
view 設定
接著我們把使用者上傳圖片表單的地方加上去,很重要的一點, multiple: true
一定要加上去,要不然會運作不了喔
views/houses/_form
> <%= form_with model: @house do |f| %>
> <%= f.file_field :images, multiple: true, class: 'form-field' %>
> <% end %>
controller 設定
最後,我們把強參數加上去,這樣才可以讓圖片新增進來
class HousesController < ApplicationController
#...省略
private
def params_house
params.require(:house).permit(:title, :content, images: [])
end
end
環境設定 -> 避免新增圖片的時候刪掉之前的圖
額外提醒,也超重要,這邊一定要加上這個,才能避免你每次在新增圖片的時候,前面新增的圖片都不見
# config/environments/development.rb
config.active_storage.replace_on_assign_to_many = false
解決多圖片上傳的問題,這一篇文章有寫 https://stackoverflow.com/questions/61933070/how-to-edit-multiple-attached-images-using-activestorage-has-many-attached-in
增加圖片限制
安裝插件
一定要安裝下面這個插件,等等驗證圖片大小才能使用
$ bundle add active_storage_validations
文件在這邊 - https://github.com/igorkasyanchuk/active_storage_validations
model 設定
class House < ApplicationRecord
has_many_attached :images do |attachable|
# 每張圖是固定size
attachable.variant :thumb, resize_to_limit: [100, 100]
attachable.variant :normal, resize_to_limit: [300, 300]
# 每張圖會依照比例縮放
attachable.variant :standard, resize_to_fill: [1200, 900]
attachable.variant :first, resize_to_fill: [1200, 904]
end
validates :images, attached: true, size: {less_than: 1.megabytes, message: '不能超過1MB'}
end
view 設定
views/houses/_form
> <%= form_with model: @house do |f| %>
> <%= f.file_field :images, multiple: true, accept: 'image/png, image/gif, image/jpeg', maxlength: 1.megabytes, class: 'form-field' %>
> <% end %>