【Rails】俺はform_withと分かち合いたい
form_with is 何?
form_withとは、railsで情報を送信するためのヘルパーメソッドです。 form_withを使うことにより、簡単に入力フォームに必要なHTMLを作成することができます。
特定のコントローラーで任意のデータを受け取りたい(urlオプションの指定)
特定の画面のフォームから送られてきた値を任意のコントローラーで利用したい場合は以下のようにurlオプションを指定してコントローラーを指定して、必要ならmethodオプションを指定してHTTPメソッド(=アクション)を指定できる。
<%= form_with url: users_path, method: :get do |form| %>
<!--フォーム内容 -->
<% end %>
生成されるHTML
<form action=”/users” method=”get”>
・・・
</form>
送られてきたデータをDBに保存して永続化したい(modelオプションの指定)
フォームから送られてきたparamsをDBに保存したい場合は、保存したい対象のモデルをmodelおオプションに指定する。methodオプションは指定がなかった場合POSTがデフォルトのHTTPメソッドとして選択される。
<%= form_with model: User.new do |form| %>
<%= form.text_field :name %>
<%= form.number_field :age %>
<%= form.submit %>
<% end %>
生成されるHTML
<form action=”/users” method=”post”>
<input type="text" name="user[name]" id="user[name]">
<input type="number" name="user[age]" id="user[age]">
<input type="submit" name="commit" value="保存する" data-disable-with="保存する">
</form>
渡ってくるparams
params
=> <ActionController::Parameters {
"utf8"=>"✓",
"authenticity_token"=>"<token>",
"user"=>{"name"=>"garasi", "age"=>"29"},
"commit"=>"送信",
"controller"=>"users",
"action"=>"create"
} permitted: false>
modelオプションが指定されている場合のデフォルトの挙動
- 該当のモデルオブジェクトから特定したcontroller・アクションに対するpostリクエストの送信
- 渡されたインスタンスが空なら
POST
, IDを持っていればPATCH
がHTTPメソッドとして指定される(methodオプションで任意のHTTPメソッドを指定もできる) - ActiveRecordと連携してモデル名とモデルの属性名をinputのname属性に付与する
Rails 5.1以前のformヘルパー
form_tag(DBへの永続化が不要な場合に利用)
form_tagはフォームに入力されたデータを保存する必要がない時に使われます。
<%= form_tag('/main', method: :post) do %>
<input type="text" name="nickname">
<input type="submit">
<% end %>
form_for(DBへの永続化を行う場合に利用)
それに対し入力されたデータを保存する必要があるときはform_forを利用します。
<%= form_for(@user) do |f| %>
<%= f.text_field :name %>
<%= f.submit %>
<% end %>
- form_forでは
FormBuilderオブジェクト
のヘルパーメソッドを使用できる - modelとurlの指定により用途の使い分けを可能にし、書き方を統一したのがform_with
- Rails5.1以降のアプリケーションでは基本的にform_withで書くのが一般的
- 昔のプロダクトでform_tag, form_forを利用している箇所があった場合に、出力されるhtmlがイメージできる程度にはなっておく必要がある
ネストしたモデルへの指定
ルーティングでネストを定義している時は記述が変わる。
記事に関するコメントを投稿するフォームを例にあげてみる。まずはコントローラーのインタンス変数の定義。
def new
@article = Article.find(params[:article_id])
@comment = Comment.new
end
def edit
@article = Article.find(params[:article_id])
@comment = Comment.find(params[:id])
end
コメントは必ずいずれかの記事に紐づいているので、どの記事のコメントなのかという情報が必要となる。
そのため@article = Article.find(params[:article_id])
でコメントする記事を取得。ビュー側は下記のように引数に配列を渡す形式となる。
<%= form_with model: [@article, @comment] do |form| %>
<%= form.text_field :text %>
<%= form.submit %>
<% end %>