Active Storageで複数画像をアップロード
以前、Active Storageで画像をアップロードという記事を書いたのですが、
今回は複数の画像をアップロードしてみます。
準備
rails new images_app cd images_app rails g scaffold User name:string
rails newしてscaffoldします。
rails active_storage:install
でactive_storage_blobs
とactive_storage_attachments
の2つのテーブルが作成されるマイグレーションファイルが生成されるので
rails db:migrate
migrateします。
slimとsimple_formを使うのでGemfileにslim-rails
、html2slim
、simple_form
を記述し、mini_magick
も必要なのでコメントアウトを外します。
bundle install
して
bundle exec erb2slim app/views -d
でerbファイルをslimファイルに変換します。
これで準備OKです。
モデル
Userが画像を複数持てるようにしたいので
# user.rb class User < ApplicationRecord has_many_attached :images end
has_many_attached
で関係を設定します。
images
の部分は任意の複数形の単語を名付けます。
コントローラ
images
を受け取れるようにストロングパラメータを設定します。
def user_params params.require(:user).permit(:name, images: []) end
permitにimages: []
を追加しました。
複数の画像が送信された時、[]の中に配列の形で入ります。
ちょっと分かりづらいですが、
"images"=>[#<ActionDispatch::Http::UploadedFile:0x00007fcb8b360e08…
のところです。
次は複数アップロードされた画像を個別に削除できるようにしたいので、そのためのコントローラを作成します。
Userが持つファイルの制御なので、user/attachments_controller.rb
とし、画像削除のためのdestroyアクション
を作成します。
# user/attachments_controller.rb class User::AttachmentsController < ApplicationController def destroy image = ActiveStorage::Attachment.find(params[:id]) image.purge @user = User.find(params[:user_id]) redirect_to user_path(@user) end end
ActiveStorage::Attachment.find(params[:id])
で画像を取ってきて、
purge
で削除です。
purge
はActiveStorageが用意しているメソッドで、添付ファイルを削除してくれます。
ルーティング
# routes.rb Rails.application.routes.draw do root 'users#index' resources :users do resources :attachments, controller: 'user/attachments', only: %i[destroy] end end
usersが持つattachments、という意味でネストさせています。
ビュー
# index.html.slim p#notice = notice h1 | Users table thead tr th | Name th[colspan="3"] tbody - @users.each do |user| tr td = user.name td - if user.images.attached? - user.images.each do |image| = image_tag image.variant(resize:'100x100').processed td = link_to 'Show', user td = link_to 'Edit', edit_user_path(user) td = link_to 'Destroy', user, method: :delete, data: { confirm: 'Are you sure?' } br = link_to 'New User', new_user_path
# show.html.slim p#notice = notice p strong | Name: = @user.name p strong | Images: - if @user.images.attached? - @user.images.each do |image| = image_tag image.variant(resize:'100x100').processed = link_to 'Destroy', user_attachment_path(@user.id, image.id), method: :delete = link_to 'Edit', edit_user_path(@user) | | = link_to 'Back', users_path
# _form.html.slim = simple_form_for user do |f| = f.error_notification = f.input :name = f.input :images, as: :file, input_html: { multiple: true } - if @user.images.attached? - @user.images.each do |image| = image_tag image.variant(resize:'100x100').processed = link_to 'Destroy', user_attachment_path(@user.id, image.id), method: :delete br = f.button :submit, 'Submit'
複数画像のアップロード、個別の削除ができました。
最後に
attachments_controllerの中で@userを定義してないのにredirect_toのpathの引数に@userを入れたり、
画像の個別削除のlink_toのpathの引数を間違ってたり、
初歩的なところでつまづいて時間が溶けてしまいました。
解決した後に冷静になってみればわかるんですけどね…
では今回は以上です。ありがとうございました。