一次ソースはこちらです。
#問題
出品した商品(item)の画像を削除したいが、削除ボタンを押し更新ボタンを押しても削除できない
.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"がついた画像を削除するようにしているよ!(チェックボックスは隠してます)
#####モデル
accepts_nested_attributes_for :images, allow_destroy: true
accepts_nested_attributes_for
を使用し、paramsのimages_attributes:キー内で値を取り、送ることで親モデル(item)に紐つく子モデル(image)の削除、更新を行える。
allow_destroy: true
で_destroyキーが使えるようになる。
#####コントローラー
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]
を記述
#原因追求
コントローラー
items_controller.rb
def update
binding.pry #デバック
if @item.update(item_params)
redirect_to item_path(@item)
else
flash.now[:alert] = '画像を1枚以上添付してください'
redirect_to edit_item_path(@item)
end
end
def update
binding.pry #デバック
if @item.update(item_params)
redirect_to item_path(@item)
else
flash.now[:alert] = '画像を1枚以上添付してください'
redirect_to edit_item_path(@item)
end
end
binding.pryを使用し、更新ボタンを押した時のparams中身をターミナルで確認する
ターミナル
※横スクロール長くてすみません。
※配列の添字(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"}},
今回は5枚ある画像から2、3、4枚目を削除した。
しかし、paramsに入る内容は"4"=>{"_destroy"=>"0", "id"=>"50"}
までで良いはずだが、不要な"5"=>{"_destroy"=>"0"}}
が入ってしまっている。
("5"は一番右の新規画像追加用のカメラマークのこと)
ブラウザ
この不要な"5"をChromeの検証ツールElementsで確認してみると
不要なhtmlタグみっけ
checkboxによりこのタグがある。
nameがつけられparamsに入ってしまっていた。
#解決方法
- if @item.images[i.index][:content].present?
をfields_forの直下に持ってきて、既存の画像のみにチェックボックスが付与されるように分けよう!!
.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を外して更新すると削除できました!