patorashのブログ

方向性はまだない

ActiveStorageで添付した画像をupdateで削除する

Rails 6.0でとあるアプリを作っているのですが、ActiveStorageを使って画像を添付しています。登録は比較的簡単に行えたのですが、画面から画像のみ削除する方法がいまいちわからなかったので調査しました。

コード(修正前)

モデル

複数の画像が添付できるように、has_many_attachedにしています。

class Post < ApplicationRecord
  has_many_attached :images
end

ビュー

simple_formを使っています。画像はActiveStorageのダイレクトアップロードでアップロードしています。

= simple_form_for(@post) do |f|
  = f.error_notification

  .form-inputs
    = f.input :title
    = f.input :content
    .mb-3
      = f.label :images
      = f.file_field :images, direct_upload: true, multiple: true, accept: 'image/*'
  .form-actions
    hr
    = f.button :submit, data: {disable_with: t('helpers.button.disable_with')}, class: 'btn-primary mr-2'
    = link_to t('helpers.links.cancel'), posts_path, class: 'btn btn-secondary'

コントローラー

特に変わりはないのでstrong_parametersのところだけ書いておきます。

class PostsController < ApplicationController
  # 略

  private

  def post_params
    params.require(:post).permit(
        :title,
        :content,
        images: [],
    )
  end
end

やろうとしたアイデア

こういうモデルの子になるデータの追加・削除はaccepts_nested_attributes_forを使うのが順当だろうと思いました。

試したこと(失敗したやつ)

モデルを以下のように修正。

class Post < ApplicationRecord
  has_many_attached :images
  accepts_nested_attributes_for :images, allow_destroy: true
end

ビューを以下のように修正。

= simple_form_for(@post) do |f|
  / 略
  .form-inputs
    / 略
    .mb-3
      = f.label :images
      = f.file_field :images, direct_upload: true, multiple: true, accept: 'image/*'
    .row.mb-3
      = f.fields_for :images do |image|
        .col.col-sm-6.col-md-4.mb-3
          = image.hidden_field :id
          .form-check
            label
              = image.check_box :_destroy, { class: 'form-check-input mr-1', checked: false }, true, false
              | 削除する
          = image_tag url_for(image.object), class: 'img-thumbnail rounded'
  / 略

こうすると、accepts_nested_attributes_for:imagesなんていう関連はない!と言われて落ちます。

しかし、AcitveStorage::Attachmentモデルと関連があるはず…なので、次を試みます。

試したこと(成功したやつ)

モデルを以下のように修正。

class Post < ApplicationRecord
  has_many_attached :images
  accepts_nested_attributes_for :images_attachments, allow_destroy: true
end

ビューを以下のように修正。

= simple_form_for(@post) do |f|
  / 略
  .form-inputs
    / 略
    .mb-3
      = f.label :images
      = f.file_field :images, direct_upload: true, multiple: true, accept: 'image/*'
    .row.mb-3
      = f.fields_for :images_attachments do |image|
        .col.col-sm-6.col-md-4.mb-3
          = image.hidden_field :id
          .form-check
            label
              = image.check_box :_destroy, { class: 'form-check-input mr-1', checked: false }, true, false
              | 削除する
          = image_tag url_for(image.object), class: 'img-thumbnail rounded'
  / 略

コントローラーもstrong_parametersを修正します。

class PostsController < ApplicationController
  # 略

  private

  def post_params
    params.require(:post).permit(
        :title,
        :content,
        images: [],
        images_attachments_attributes: [ :id, :_destroy ],
    )
  end
end

これで、更新時にファイルの削除ができるようになりました。

動作検証

紫陽花と桜の画像をアップ済みです。そこから、紫陽花の画像を削除してみます。

f:id:patorash:20201202154337p:plain

showの画面を都合で見せられないのですが、再び更新画面にきたときには桜の画像のみ残っています。

f:id:patorash:20201202154425p:plain

削除に成功です。