はじめに
ユーザー情報編集画面を作成した時に、編集画面上で複数画像の削除ができる機能を実装しました。
その後Deviseを導入し、ユーザー情報編集画面をDeviseのRegistrations/edit.html.erbの方に置き換えた時に、この画像削除機能がうまく機能しなくなった時のお話です。
画像の操作はActiveStorageを使っています。
今回はこちらのアプリ上での削除機能の実装です。
Web URL: https://scouter.fun
GitHub URL: https://github.com/delicha/scouter
修正後
環境
macOS Big Sur(11.6.6)rails 6.1.6
ActiveStorage 6.1.5.1
原因
複数画像の削除機能は以下のサイトを参考に作りました。
https://prograshi.com/framework/rails/active-storage/
class User < ApplicationRecord
(Devise導入後に追加した部分)
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
(ここまで)
...
has_one_attached :image
has_many_attached :sub_images
...
end
<tr>
<th><%= f.label :sub_images, 'サブ画像', class: "text-muted" %><br /><span class="small text-info">(サブ画像は3枚まで選択可)</span></th>
<td>
<%= f.file_field :sub_images, multiple: true, class: "form-control" %>
<% if @user.sub_images.attached? %>
<div class="d-flex justify-content-start mt-2">
<% @user.sub_images.each do |sub_image| %>
<%= form.check_box :sub_image_ids, { multiple: true }, sub_image.id, false %>
<label for="user_sub_images_<%= sub_image.id %>">
<%= image_tag sub_image.variant(resize: "30x30"), class:'px-2 rounded-circle' %>
</label>
<% end %>
<p class="small">選択画像</p>
</div>
<% else %>
<span class="small">画像がありません。</span>
<% end %>
</td>
</tr>
上記で、ユーザー編集画面上で複数画像の選択と削除が実装できたのですが、Deviseを導入し、ユーザー編集画面をRegistrations/edit.html.erbに変更した後にこの機能が使えなくなってしまいました。
原因は、
<%= form.check_box :sub_image_ids, { multiple: true }, sub_image.id, false %>
のところでうまくsub_image_idsなどが渡せていないようでしたが、なぜそれがDevise(はじめて)の導入によって起こってしまったのかまではわかりませんでした。
結論
とりあえず、
<%= form.check_box :sub_image_ids, { multiple: true }, sub_image.id, false %>
は、Registrations/edit.html.erbから削除してユーザー情報編集画面上での削除を諦め、ユーザープロフィール画面上で画像を削除できるように仕様を変更。
以下のサイト(英語)を参考に、purgeメソッドを新たに作成して、画像を個別に削除できるように実装しました。
※以下詳しくはGithubの方をご覧ください。
class AttachmentsController < ApplicationController
def purge
attachement = ActiveStorage::Attachment.find(params[:id])
attachement.purge
redirect_back fallback_location: root_path, notice: "画像を削除しました。"
end
end
class UsersController < ApplicationController
...
def purge_image
@user.image.purge
redirect_back fallback_location: user_path(@user), notice: "画像は削除されました。"
end
end
delete "attachements/:id/purge", to: "attachments#purge", as: "purge_attachment"
...
<% @user.sub_images.drop(1).each do |attachment| %>
<div class="carousel-item">
<%= image_tag attachment.variant(resize: "300x400"), class: 'rounded border mx-2 mb-3' %>
<% if current_user.id == @user.id %>
<p class="small">
<%= link_to "▲画像削除", purge_attachment_path(attachment), class: "btn-light btn-sm rounded-pill", method: :delete, data: { confirm: "「画像を削除します。よろしいですか?"} %>
</p>
<% end %>
</div>
<% end %>
...
実装した結果、以下のようになりました。
どなたかの参考になれば幸いです!
もし、Deviseを使った同じような状況でコードをこのように変更したらできるよ!というのがありましたら、ぜひ教えていただけたらうれしいです!
参考記事
https://prograshi.com/framework/rails/active-storage/
https://youtu.be/QcaSdsXtdvo
https://youtu.be/kNRU3CD0oc0