【Rails】form_withの使い方
form_withの使い方について復習。と、理解を深める。
form_tagとform_for
たまに見かけるform_withによく似た形のフォームヘルパーですが、これらは少し古いもので、今ではform_withがこれら2つの役割をどっちも担ってくれているため、基本的にはform_tagとform_forは使わない。
簡単に説明しておくと、
form_tag は関連するモデルが無く、入力されたデータを保存しない場合に使用。
form_for は関連するモデルがあって、入力されたデータを保存する場合に使用。
form_with
モデルの有無に関わらずform_withで入力フォームを作成できる。
- 関連モデルが無いform_withの記述(urlを指定)
<%= form_with url: users_path do |form| %> <%= form.text_field :nickname %> <%= form.submit %> <% end %>
- 関連モデルがあるform_withの記述(modelを指定)
<%= form_with model: @user do |form| %> <%= form.text_field :nickname %> <%= form.submit %> <% end %>
form_withの引数にモデルクラスのインスタンスを指定すると、自動的にどのURLに飛ぶかを判断してくれる。ここで言うと、ユーザー情報が無ければこれから作るんだなと思ってcreateアクションに行き、ユーザー情報が既に存在していれば更新するんだなと思ってupdateアクションに行くようにしてくれる。(引数となるインスタンス変数を以下のように定義しているため)
def new @user = User.new end def edit @user = User.find(params[:id]) end
FormBuilderオブジェクト
form_withの引数にある@userの情報を持っている「form」のこと。(もしくは「f」)
これによって、text_fieldやsubmitといったFormBuilderオブジェクトのヘルパーメソッドを使うことができる。
各formで取得した情報ををブロック変数の中のformに集めてコントローラーに持っていくというイメージかな。
ネストしているとき
例えば、Tweetに対するコメントのように、ルーティングでネスト構造になっているときは、以下のように引数に配列で変数を渡す記述をする。
<%= form_with model: [@tweet, @comment] do |form| %> <%= form.text_field :text %> <%= form.submit %> <% end %>
このときのコントローラーでは、@tweetと@commentの両方を定義しておく。
def new @tweet = Tweet.find(params[:tweet_id]) @comment = Comment.new end def edit @tweet = Tweet.find(params[:tweet_id]) @comment = Comment.find(params[:id]) end
methodオプション
送信するHTTPメソッドを指定する。デフォルトはPOSTなので省略することが多い。
データ削除のときなどに以下のように記述する
<%= form_with model: @tweet, method: :delete do |form| %> <%= form.text_field :text %> <%= form.submit %> <% end %>
localオプション
送信方法を指定する。デフォルトではリモートフォームになっていて、非同期通信のXHR(Ajax)リクエストで送信される。
XHRが何の略か分からない人は、local: true を指定して、リモートフォームを無効にしておく。
終わりに
form_withの歴史をほんのちょっと知ることができました。form_withの記述がややこしく感じた理由もわかりました。モデルの状況や通信方法などを意識しながら、正しい記述ができるようにしていきたいと思います。