【Rails】form_tagとform_for

form_tag と form_forの違いについて、まとめていきます。

■form-tagについて
  • フォームの開始/終了タグを作成する。
<% form_tag(:controller => "hoge", :action => "fuga") do -%>
<% end -%>
  • 実行結果↓
<form action="/hoge/fuga" method="post">
</form>

※このメソッドでフォームを作成する際には、<%= … %> ではなく、<% … %>で囲む。

  • 第2引数にはformタグの属性を指定するパラメータを指定する。
<% form_tag({:controller => "hoge", :action => "fuga"},
            {:multipart => true}) do -%>
<% end -%>
  • 実行結果↓
<form action="/hoge/fuga" entype="multipart/form-data" method="post">
</form>
  • サブミットボタンを作成する。

submit_tagメソッドで作成する。第1引数にはボタンのラベルを指定。第2引数にはinputタグの各種属性を指定できる。

submit_tag("決定", :class => "hoge")

※画像形式のサブミットボタンは、image_submit_tagメソッドで作成する。

  • 実際の仕様例
<% form_tag({:action => "create"}, {multipart => true}) do -%>
  お店の名前 
  <%= text_field_tag "shop[name]", "", :id => "shop_name" %><br />

  アイコン
  <%= file_field_tag "shop[icon]", :id => "shop_icon" %><br />

  <%= submit_tag "作成" %>
<% end -%>
  • 上記のフォームの各値は、params[:shop]に設定される。よってコントローラーでは以下のようなHashで受け取ることが出来る。
params[:shop] # => {:name => "店名", :icon => #<StringIO:0x19eb780>}
params[:shop][:name] # => "店名"
params[:shop][:icon] # =>  #<StringIO:0x19eb780>

※iconの画像データは任意のファイルを示しています。

■form_forについて
  • 『モデルに対応するフォーム』を簡単に作るためのヘルパーメソッド。
  • モデルに対応するフォームで必要となる機能
    • name属性に[]のついた入力項目からのリクエストを簡単に扱うための仕組みがあるので、それに適応したname属性を使う。
    • モデルオブジェクトを編集するフォームでは、入寮項目のデフォルト値として既存のモデルオブジェクトの値を使う。
    • モデルオブジェクトの検証でエラーがあった場合、その箇所を強調表示する。

※form_forメソッドはこのようなフォームを作る際に便利!

  • form_forメソッドの第1引数には、変数名を『文字列orシンボル』の形で指定。
    • FormBuilderオブジェクトが対象とするモデルオブジェクトを指定する。
    • FormBuilderオブジェクトで作成する入力項目タグのname属性の一部になる。

※つまり、form_forメソッドは第1引数で指定された名前のインスタンス変数を探し、それをFormBuilderに渡す。

  • form_forメソッドの第2引数にはformタグのための各種パラメータを指定する。ほぼ必須となるのは:urlパラメータ。
<%# @entryをもとにしたフォームを作る %>
<% @entry = Entry.new(:title => "Entry Title") %>
<% form_for(:entry, :url => {:action => "create"}) do |f| -%>
  <%= f.text_field :title %><br />
<% end -%>
  • 出力されるHTML↓
<form action=(略)>
  <input id="entry_title" name="entry[title]" type="text" value="Entry Title" />
</form>

※テキストフィールドのname属性が"entry[title]"となる。
※入力項目のデフォルト値がインスタンス変数対象のオブジェクト(@entry)のtitleの値になる。(更新用フォームに使える!)

  • 覚え方
    • 『form_for :entry』を『form for entry』つまり、『entryのためのform』を作成すると覚えると良い。
  • name属性の前半と実際のインスタンスを分けて指定する
    • name属性として使いたい文字列とインスタンス変数が一致しない場合、form_forの第2引数にローカル変数うを指定する。
<% @entry = Entry.new(:title => "Entry Title") %>
<% another_entry = Entry.new(:title =>  "Another Entry Title") %>

<%# @entryではなく、ローカル変数another_entryをもとにしたフォームを作る %>
<% form_for(:entry, another_entry,
            :url => {:action => "create"}) do |f| -%>
  <%= f.text_field :title %><br />
<% end -%>
  • 出力されるHTML↓
<form action=(略)>
  <input id="entry_title" name="entry[title]" type="text" value="Another Entry Title" />
</form>
  • このとき、フォーム内のinput要素のname属性には第一引数で指定した「entry」が使われ、その入力項目のデフォルト値にはanother_entry.titleが使われる。
■form_tag と form_forの違い
  • form_forメソッドでは、ブロック内にフォームの入力項目を作成する際に、FormBuilderオブジェクトが利用出来る!
  • form_forメソッドはブロックを使うことができるので、コードがスッキリ!!
  • ただ、融通が効くのはform_tagな気がする。。