#render :newした際に、new.html.erbが呼び出されているが、画像投稿フォームが消えてしまう。
redirect_to new_product_pathを使用すれば、問題は解決するのですが、
renderを使用した場合に画像のフォームが表示されません。
redirect_toを使用すればいいのでは思われるのですが、入力した値が消えてしまうため、
できるだけrenderで画像のフォームも表示しさせたいです。
#参考サイト
renderについて
renderとredirect_toについて
#■仮説と検証
renderした先がnewアクションだったため、うまく動かなかったのでは?
→renderした先のnewアクションではform(部分テンプレート)をrenderしているため、問題ないかと思ったが、実際は画像フォームが表示されない。
#疑問
・そもそもrender :newのアクションはnew.html.erbをそのまま反映していないのでは・・・?
・またはjavascriptがおかしいかもしれない?
#一旦自己解決したのですが、・・・以下のような疑問が残りました。
products_controller.rbの
def createの欄に
render partial:"form" ,locals: {product:new}
と記述すると画像フォームが表示されました。
試行錯誤中にできてしまったのですが、なぜ画像フォームが表示されたのかがわかりません。。。
①localsの中に記述されている変数、productはどの部分を示しているのでしょうか?
②また、:newのnewは変数の値だとは思うのですが、どのデータをひっぱってきているのでしょうか?
以下修正したcontrollerファイルです。
controller
1 2def create 3 @product = Product.new(product_params) 4 if @product.save 5 redirect_to root_path ,notice: "商品名は#{@product.name}、値段は#{@product.price}円で登録しました。" 6 else 7 flash.now[:alert] = '商品名と値段を記入してください' 8 render partial:"form" ,locals: {product:new} 9 end 10 end
上記のように記述しなおすと解決しました(画像フォームが表示されました)
もしわかる方いらっしゃいましたらご指摘ただけますと幸いです。
①localsの中に記述されている変数、productはどの部分を示しているのでしょうか?
②また、:newのnewは変数の値だとは思うのですが、どのデータをひっぱってきているのでしょうか?
#各ファイルに記述したコードです。
routes.rb
routes
1 2Rails.application.routes.draw do 3 root 'products#index' 4 resources :products, except: :show 5end 6
products_controller.rb
controller
1 2class ProductsController < ApplicationController 3 4 before_action :set_product, except: [:index, :new, :create] 5 6 def index 7 @products = Product.includes(:images).order('created_at DESC') 8 end 9 10 def new 11 @product = Product.new 12 @product.images.new 13 end 14 15 def create 16 @product = Product.new(product_params) 17 if @product.save 18 redirect_to root_path ,notice: "商品名は#{@product.name}、値段は#{@product.price}円で登録しました。" 19 else 20 flash.now[:alert] = '商品名と値段を記入してください' 21 render :new 22 #上記のnewだと画像フォームが表示されないが、redirect_to new_product_pathと記述すると、画像フォームが表示される。 23 end 24 end 25 26 def edit 27 end 28 29 def update 30 if @product.update(product_params) 31 redirect_to root_path 32 else 33 render :edit 34 35 end 36 end 37 38 def destroy 39 @product.destroy 40 redirect_to root_path 41 end 42 43 private 44 45 def product_params 46 params.require(:product).permit(:name, :price, images_attributes: [:src, :_destroy, :id]) 47 end 48 49 def set_product 50 @product = Product.find(params[:id]) 51 end 52 53end 54
application.html.erb
application
1 2<!DOCTYPE html> 3<html> 4 <head> 5 <title>フリマ</title> 6 <%= csrf_meta_tags %> 7 <%= csp_meta_tag %> 8 9 <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> 10 <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> 11 </head> 12 13 <body> 14 <% if flash[:notice] %> 15 <p class = "text-success"><%= flash[:notice] %></p> 16 <% end %> 17 <% if flash[:alert] %> 18 <p class = "text-danger"><%= flash[:alert] %></p> 19 <% end %> 20 </div> 21 <%= yield %> 22 </body> 23</html> 24
_form.html.erb
form
1 2<%= form_for @product do |f| %> 3 商品名<%= f.text_field :name %><br> 4 価格<%= f.number_field :price %><br> 5 <div id="image-box"> 6 <div id="previews"> 7 <% if @product.persisted? %> 8 <% @product.images.each_with_index do |image, i| %> 9 <%= image_tag image.src.url, data: { index: i }, width: "100", height: '100' %> 10 <% end %> 11 <% end %> 12 </div> 13 <%= f.fields_for :images do |image| %> 14 <div data-index="<%= image.index %>" class="js-file_group"> 15 <%= image.file_field :src, class: 'js-file' %><br> 16 <span class="js-remove">削除</span> 17 </div> 18 <% if @product.persisted? %> 19 <%= image.check_box :_destroy, data:{ index: image.index }, class: 'hidden-destroy' %> 20 <% end %> 21 <% end %> 22 <% if @product.persisted? %> 23 <div data-index="<%= @product.images.count %>" class="js-file_group"> 24 <%= file_field_tag :src, name: "product[images_attributes][#{@product.images.count}][src]", class: 'js-file' %> 25 <button type="button" class="js-remove" value="value">削除</button> 26 </div> 27 <% end %> 28 </div> 29 <%= f.submit "投稿する" %> 30<% end %>
new.html.erb
new
1 2<%= render partial: 'form' %>
javascript
1 2$(document).on('turbolinks:load', ()=> { 3 const buildFileField = (num)=> { 4 const html = `<div data-index="${num}" class="js-file_group"> 5 <input class="js-file" type="file" 6 name="product[images_attributes][${num}][src]" 7 id="product_images_attributes_${num}_src"><br> 8 <button type="button" class="js-remove">削除</button> 9 </div>`; 10 return html; 11 } 12 const buildImg = (index, url)=> { 13 const html = `<img data-index="${index}" src="${url}" width="100px" height="100px">`; 14 return html; 15 } 16 17 let fileIndex = [1,2,3,4,5,6,7,8,9,10]; 18 lastIndex = $('.js-file_group:last').data('index'); 19 fileIndex.splice(0, lastIndex); 20 21 $('.hidden-destroy').hide(); 22 23 $('#image-box').on('change', '.js-file', function(e) { 24 const targetIndex = $(this).parent().data('index'); 25 const file = e.target.files[0]; 26 const blobUrl = window.URL.createObjectURL(file); 27 28 if (img = $(`img[data-index="${targetIndex}"]`)[0]) { 29 img.setAttribute('src', blobUrl); 30 } else { 31 $('#previews').append(buildImg(targetIndex, blobUrl)); 32 $('#image-box').append(buildFileField(fileIndex[0])); 33 fileIndex.shift(); 34 fileIndex.push(fileIndex[fileIndex.length - 1] + 1); 35 } 36 }); 37 38 $('#image-box').on('click', '.js-remove', function() { 39 const targetIndex = $(this).parent().data('index'); 40 const hiddenCheck = $(`input[data-index="${targetIndex}"].hidden-destroy`); 41 if (hiddenCheck) hiddenCheck.prop('checked', true); 42 43 $(this).parent().remove(); 44 $(`img[data-index="${targetIndex}"]`).remove(); 45 46 if ($('.js-file').length == 0) $('#image-box').append(buildFileField(fileIndex[0])); 47 }); 48});
以上となります。
不足する情報、ファイル等々ございましたらご指摘いただけますと幸いです。
最後までみていただきありがとうございます。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。