_destroyキーの使い方 ~~親(item)の子(image)を削除する~


一次ソースは[こちら](https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html)です。
#問題
出品した商品(item)の画像を削除したいが、削除ボタンを押し更新ボタンを押しても削除できない

```edit.html.haml
  .main-items
    = form_with model: @item, local: true do |f|
      .wrapper.image-wrapper
        #image-box.image-wrapper__image-box
          = f.fields_for :images do |i|
            - if @item.persisted?
              = i.check_box :_destroy, data:{ index: i.index}, class: 'hidden-destroy'
            .image-wrapper__image-box__js.js-file_group{:id => "item_images_attributes_#{i.index}_id", data:{index: "#{i.index}"}}
              = i.label :content, class: "image-wrapper__image-box__js__label" do
                .image-wrapper__image-box__js__label__image.img_field{id: "img_field--#{i.index}", onClick: "$('#file').click()"}
                  - if @item.images[i.index][:content].present?
                    = image_tag asset_path(@images[i.index].content), class:"preview "
                  - else
                    = image_tag 'icon_camera.png', class: "image-wrapper__image-box__js__label__image__url", id: "default-img"
                = i.file_field :content, class: "image-wrapper__image-box__js__label__file js-file", id: "item_images_attributes_#{i.index}_content"
              .js-remove
                %span.js-remove__text
                  削除
```
#前準備
問題コードの
`= i.check_box :_destroy, data:{ index: i.index}, class: 'hidden-destroy'`
によって各画像のチェックボックスにチェックが入ったら_destroyに値"1"がついた画像を削除するようにしているよ！（チェックボックスは隠してます）

#####モデル
```item.rb
accepts_nested_attributes_for :images, allow_destroy: true
```
`accepts_nested_attributes_for`を使用し、paramsのimages_attributes:キー内で値を取り、送ることで親モデル(item)に紐つく子モデル(image)の削除、更新を行える。

`allow_destroy: true`で_destroyキーが使えるようになる。
#####コントローラー

```items_controller.rb
  private
  def item_params
    params.require(:item).permit(
      :name, :description, :price, :brand_id, :area, :condition, :fee, :category_id,
      :shipping_days, images_attributes: [:content, :id, :_destroy]
      ).merge(user_id: current_user.id)
  end
```
ストロングパラメーターに`images_attributes: [:content, :id, :_destroy]`を記述

#原因追求

[![Image from Gyazo](https://i.gyazo.com/5bebea4932aac4a4d91bc822f5d7b272.gif)](https://gyazo.com/5bebea4932aac4a4d91bc822f5d7b272)
<h5>コントローラー

```items_controller.rb
  def update
    binding.pry #デバック
    if @item.update(item_params)
      redirect_to item_path(@item)
    else
      flash.now[:alert] = '画像を１枚以上添付してください'
      redirect_to edit_item_path(@item)
    end
  end
```

binding.pryを使用し、更新ボタンを押した時のparams中身をターミナルで確認する


<h4>ターミナル

※横スクロール長くてすみません。
**※配列の添字(index)により一枚目は"0"から始まっています。**

```
"item"=>{"images_attributes"=>{"0"=>{"_destroy"=>"0", "id"=>"2"}, "1"=>{"_destroy"=>"1", "id"=>"47"}, "2"=>{"_destroy"=>"1", "id"=>"48"}, "3"=>{"_destroy"=>"1", "id"=>"49"}, "4"=>{"_destroy"=>"0", "id"=>"50"}, "5"=>{"_destroy"=>"0"}},
```

今回は５枚ある画像から２、３、４枚目を削除した。
しかし、paramsに入る内容は`"4"=>{"_destroy"=>"0", "id"=>"50"}`までで良いはずだが、不要な`"5"=>{"_destroy"=>"0"}}`が入ってしまっている。
("5"は一番右の新規画像追加用のカメラマークのこと)

<h5>ブラウザ

この不要な"5"をChromeの検証ツールElementsで確認してみると
[![Image from Gyazo](https://i.gyazo.com/2e78fa4d22a0ea531503ef9ca332cbed.png)](https://gyazo.com/2e78fa4d22a0ea531503ef9ca332cbed)
不要なhtmlタグみっけ

**checkboxによりこのタグがある。**
nameがつけられparamsに入ってしまっていた。

#解決方法
`- if @item.images[i.index][:content].present?`をfields_forの直下に持ってきて、既存の画像のみにチェックボックスが付与されるように分けよう！！

```edit.html.haml
  .main-items
    = form_with model: @item, local: true do |f|
      .wrapper.image-wrapper
        #image-box.image-wrapper__image-box
          = f.fields_for :images do |i|
            - if @item.images[i.index][:content].present?
              - if @item.persisted?
                = i.check_box :_destroy, data:{ index: i.index}, class: 'hidden-destroy'
              .image-wrapper__image-box__js.js-file_group{:id => "item_images_attributes_#{i.index}_id", data:{index: "#{i.index}"}}
                = i.label :content, class: "image-wrapper__image-box__js__label" do
                  .image-wrapper__image-box__js__label__image.img_field{id: "img_field--#{i.index}", onClick: "$('#file').click()"}
                    = image_tag asset_path(@images[i.index].content), class:"preview "
                .js-remove
                  %span.js-remove__text
                    削除
            -else
              .image-wrapper__image-box__js.js-file_group{:id => "item_images_attributes_#{i.index}_id", data:{index: "#{i.index}"}}
                = i.label :content, class: "image-wrapper__image-box__js__label" do
                  .image-wrapper__image-box__js__label__image.img_field{id: "img_field--#{i.index}", onClick: "$('#file').click()"}
                    = image_tag 'icon_camera.png', class: "image-wrapper__image-box__js__label__image__url", id: "default-img"
                  = i.file_field :content, class: "image-wrapper__image-box__js__label__file js-file", id: "item_images_attributes_#{i.index}_content"
                .js-remove
                  %span.js-remove__text
                    削除
```

これでparamsを確認すると

```
"item"=>{"images_attributes"=>{"0"=>{"_destroy"=>"0", "id"=>"2"}, "1"=>{"_destroy"=>"1", "id"=>"47"}, "2"=>{"_destroy"=>"1", "id"=>"48"}, "3"=>{"_destroy"=>"1", "id"=>"49"}, "4"=>{"_destroy"=>"0", "id"=>"50"}}
```

"5"が入ってないOK

binding.pryを外して更新すると削除できました！