form_withの使い方
form_withの使い方
[コントローラにモデルのインスタンスが定義されている場合でデータを保存する場合]
ex)
[app/controllers/boards_controller.rb] def new @board = Board.new end def create @board = current_user.boards.new(board_params) if @board.save redirect_to boards_url, success: (t '.success') else flash.now[:danger] = (t '.fail') render :new end end def edit @board = current_user.boards.find(params[:id]) end def update @board = current_user.boards.find(params[:id]) if @board.update(board_params) redirect_to @board, success: (t '.success') else flash.now[:danger] = (t '.fail') render 'edit' end end
[app/views/boards/new.html.erb] <% content_for(:title, (t '.title')) %> <div class="container"> <div class="row"> <div class="col-lg-8 offset-lg-2"> <h1><%= (t '.title') %></h1> <%= render partial: 'form', locals: { board: @board } %> </div> </div> </div>
[app/views/boards/edit.html.erb] <% content_for(:title, @board.title) %> <div class="container"> <div class="row"> <div class="col-lg-8 offset-lg-2"> <h1><%= (t '.title') %></h1> <%= render partial: 'form', locals: { board: @board } %> </div> </div> </div>
[app/views/boards/_form.html.erb] <%= form_with model: board, local: true do |f| %> <%= render 'shared/error_messages', { object: f.object } %> <div class="form-group"> <%= f.label :title %> <%= f.text_field :title, class: "form-control" %> </div> <div class="form-group"> <%= f.label :body %> <%= f.text_area :body, class: "form-control", rows: "10" %> </div> <div class="form-group"> <%= f.label :image %> <%= f.file_field :image, onchange: 'previewImage()', class: 'form-control mb-3', accept: 'image/*' %> <%= image_tag board.image.url, id: 'preview', size: '300x200' %> </div> <%= f.submit class: "btn btn-primary" %> <% end %>
上記のような場合は、
[form_with model: コントローラで取得しているインスタンス名]と記載する事で、以下のようになる。
・[new.html.erb]よりformファイルが読み込まれる場合は、newアクションで取得しているインスタンスが[@board = Board.new]となっており、
[newメソッド]がある事により、railsが自動で予測してフォーム情報がcreateアクションにいくパスを自動生成する。
・[edit.html.erb]よりformファイルが読み込まれる場合は、editアクションで取得しているインスタンスが[@board = current_user.boards.find(params[:id])]となっており、
[findメソッド]がある事により、railsが自動で予測してフォーム情報がupdateアクションにいくパスを自動生成する。
※データの保存可否については、form_withに渡しているインスタンス変数がUser.newとなっているので、railsが自動でUserモデルを指定している。
[自動生成されるパスとは違う場所にフォーム情報を送る場合でデータを保存する場合]
ex)
[app/views/comments/_form.html.erb] <%= form_with model: [board, comment], local: true do |f| %> <%= render 'shared/error_messages', object: f.object %> <div class="form-group"> <%= f.label :body %> <%= f.text_area :body, class: 'form-control' %> </div> <%= f.submit (t 'defaults.post'), class: 'btn btn-primary' %> <% end %>
[app/controllers/comments_controller.rb] def create comment = current_user.comments.new(comment_params) if comment.save redirect_to board_url(comment.board_id), success: (t '.success') else redirect_to board_url(comment.board_id), danger: (t '.fail') end end
[app/views/comments/_form.html.erb]を以下のように記載してしまうと、本来ならデータの行き先が、ルーティングをネスト化している関係で(/boards/:board_id/comments)に行かなくてはいけないが、comments_pathに行ってしまうので、url:[board, comment]と記載することでデータの行き先のパスを( /boards/:board_id/comments)に指定。
[app/views/comments/_form.html.erb] <%= form_with model: comment, local: true do |f| %>
上記のurlでフォーム情報の行き先のパスを指定するだけだとフォームのデータを保存できないので、データを保存する先のmodelを特定するために[model:(コントローラで取得しているインスタンス変数名)を記載しなければならない。(データを保存するためには、モデルを特定しなければいけない。)
主にこのパターンは、ルーティングをネスト化している場合などに使う。
[フォームの情報を保存しない場合]
[app/views ファイル] <%= form_with url: パス do |f| %>
※ポイント
フォームの情報を保存する為には、form_withでcreateアクションなどへのパスだけでなく[model: モデルのインスタンス]で保存するモデルを特定しなければいけない。
参考記事:
【Rails】form_withの使い方を徹底解説! | Pikawaka - ピカ1わかりやすいプログラミング用語サイト