質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

1回答

1806閲覧

Railsでrender :newした際に、画像のフォームが表示されなくなってしまう

pontarou3

総合スコア18

Ruby

Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

1クリップ

投稿2020/03/02 02:10

編集2020/03/02 02:44

#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});

以上となります。
不足する情報、ファイル等々ございましたらご指摘いただけますと幸いです。

最後までみていただきありがとうございます。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

全貌はこれから見ますが、まず
locals: {product:new}
これは product と :new ではなく、 product: と new です
form で product を参照したときに、 new を渡します。
newはなにものか?!
ここでエラーが起きなかったとすると、new method の結果ですが、Controllerのnewではなく、Controllerのインスタンスのnewということになるのでちと考えさせてください。

追記
これかな
render :new ではなく render action: :new

投稿2020/03/03 01:53

編集2020/03/03 01:54
winterboum

総合スコア23284

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問