[Rails] carrierwave uploader
keywords: file upload
產生 uploader
執行下面其他步驟前,要先建立 uploader
:
# create app/uploaders/fieldname_uploader.rb
rails generate uploader Avatar
上傳單一檔案
Generator
rails g migration add_avatar_to_users avatar:string
Model
在 model 中掛入 uploader
# ./app/models/user.rb
class User < ActiveRecord::Base
mount_uploader :avatar, AvatarUploader
end
Controller
# ./app/controllers/users_controller.rb
def user_params
params.require(:user).permit(:name, :avatar)
end
View
在 View 中使用,這時候送出表單,就會自動將檔案上傳到 ./public/uploads/<fieldName>
資料夾中,同時將檔名存入相對應的 table field 中。
<!-- ./app/views/users/_form.html.erb -->
<%= form_with(model: user, local: true) do |form| %>
<div class="field">
<%= form.label :avatar %>
<%= form.file_field :avatar, id: :product_avatar %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
利用在 View 中可以透過:
product.avatar # 取得圖檔相對路徑
product.avatar.url # 取得圖檔相對路徑(和上面一樣)
product.avatar.current_path # 取得圖檔絕對路徑
product.avatar_identifier # 取得檔名(是用底線 _ )
product.avatar.file.nil? # 判斷檔案是否存在
注意:
product.avatar
永遠不會回傳nil
,即使沒有和它關連的圖片也一樣。可以透過product.avatar.file.nil?
來檢驗是否有相關連的圖片。
上傳多個檔案 multiple files upload
Generator
上傳多個檔案時,欄位名稱加上 s ,且欄位格式為 json
rails g migration add_avatars_to_users avatars:json
rails db:migrate
Model
原本的 mount_uploader
和 :avatar
都要變成複數:
# ./app/models/user.rb
class User < ActiveRecord::Base
mount_uploaders :avatars, AvatarUploader
end
Controller
# 這是透過 AJAX 上傳圖檔
# ./app/controllers/users_controller.rb
def update_images
add_more_images(params[:product][:photos]) unless params[:product][:photos].nil?
msg = {
:status => 'get data',
:photos => @product.photos.map(&:url)
}
render :json => msg
end
# controller
# new_images 代入 params 傳入的圖檔,例如 params[:product][:photos]
def add_more_images(new_images)
images = @product.photos
images += new_images
@product.photos = images
@product.save
end
View
file_field
要記得加上 multiple: true
:
<!-- ./app/views/users/_form.html.erb -->
<%= form_with(model: user, local: true) do |form| %>
<div class="field">
<%= form.label :avatars %>
<%= form.file_field :avatars, id: :user_avatars, multiple: true %>
</div>
<div class="actions">
<%= form.submit %>
</div>
<% end %>
透過 form.file_field
產生的 input tag 會長像下面這樣,其中 name 會是 name="user[avatars][]"
:
<input id="user_avatars" multiple="multiple" type="file" name="user[avatars][]" />