form_tagとform_forの違い

【結論】
・form_tagとform_forは、フォームを簡単に生成する為のメソッド
・form_tagとform_forの違いは、下記の通り
 form_tag・・・汎用的なメソッド。
         検索フォームなどで使用する。
 form_for・・・データベースへの登録/更新に特化しており、
         投稿の新規作成・編集などで使用する。
・form_forは、指定したモデルオブジェクトの状態から、
 適切なフォームの送信先を自動で判断する為、
 新規作成・編集画面で同じコードを流用させる事ができる。


【目次】

【本題】

概要

form_forとform_tagは、どちらもビューヘルパーと呼ばれ、
簡単にフォームのビューを作成してくれるメソッドです。

使い方はある程度理解したのですが、どういった違いがあるのか、
明確に説明するとなると難しかったので、ここで整理します。

まず、それぞれの違いは、
簡単に説明すると、下記の通りです。

form_tag・・・汎用的なフォームを作成
form_for・・・モデルオブジェクトを編集することに特化したフォームを作成

次に、個々の詳しい仕組みを見ていきます。

form_tagの仕組み

form_tagを利用する場合、下記の様に記述します。

form_tag(リンク先 [オプション]) do
end

オプションで様々な指定ができ、
例えば「:method」でHTTPメソッドを、
「:class」でclassを指定することなどができます。

下記は検索フォームの一例です。

記述例1

<%= from_tag( { :controller => keyword, action => search}, :id => fm, :class => search) do %>
#省略
<% end %>

ハッシュロケットを使わずに、下記の様に記述することも可能です。

記述例2

<%= from_tag( { controller: :keyword, action: :search}, id: :fm, class: :search) do %>
#省略
<% end %>

この様に、コントローラーとアクションで、リンク先(フォームの送信先)を
指定することも出来ますし、相対パスでも指定は可能です。

また、データベースに登録したり、編集する為のフォームも作成可能です。
その際、モデルの内容を編集するフォームと、
それに対応したアクションメソッドが必要です。

下記は、新規にbookモデルに情報と登録するフォームと、
それに対応したアクションメソッドです。

記述例3
「view」

<%= form_tag(action: :create) do %>
#省略
<%= label :book, :isbn %>
<%= text_field :book, :isbn, size: 25% %>
#省略
<%= label :book, :title %>
<%= text_field :book, :title, size: 25% %>
#省略
<% end %>

「controller」

def index
 @book = Book.new
End

def create
 @book = Book.create(:isbn, :title)
end

「action: :create」という記述により、
アクションメソッドのcreateに、リンク先を設定して、
データベースへフォームに入力した内容を登録できます。

なお、form_forでは、リンク先を指定しなくても、
自動的に適切な送信先を選択
してくれます。

また、このフォームのコードを見ると、
何度もbookオブジェクトを明記しているのが分かります。

form_forでは、こういった手間は解消できます。





form_forの仕組み

form_forは、下記の様に記述します。

form_for(モデルオブジェクト [, オプション]) do |f|
end

モデルオブジェクトとは、先ほどの記述例3にあった
コントローラーの「@book」にあたります。
名前に対応するデータベースのデータです(booksテーブル)


では、form_forで、
先ほどのform_tagの記述を書き換えます。

記述例4

<%= form_for(@book) do |f|  %>
#省略
<%= f.label :isbn %>
<%= f.text_field :isbn, size: 25% %>
#省略
<% end  %>

「controller」

def index
 @book = Book.new
End

def create
 @book = Book.create(:isbn, :title)
end

def edit
 @book = Book.find
End

def update
 @book = Book.update
end


この様に、「book」を何度も明記しなくなった分、
コードが短くなりました
これが、form_forのメリットの一つです。


そして、もう一つのメリットは、このフォームは、
新規作成と編集画面の両方で流用できます。

先ほどの記述例には、editとupdateという編集用の
メソッドも記載していましたが、
あれらも中身は違えど、同じ「@book 」という
モデルオブジェクトを生成しています。

更に、form_forは、モデルオブジェクトが
データベースへ既に登録されているかを判別して、
登録済の場合、update(更新)
未登録の場合、create(新規)
という様に、
フォームの送信先を自動的に振り分けてくれます。

なので、全く同じコードでも、
新規作成と編集画面の両方で流用ができるのです。

なお、流用する場合は、部分テンプレート化して、
editとnewのHTMLファイルで呼び出せる様に
設定する必要があります。


使い分けについて

モデルオブジェクトと編集する場合の、
form_forのform_tagに対する優位性は下記の通りです。

・コードが短く済む
・新規作成と編集画面を、部分テンプレートで共有できる

なお、form_forはモデルオブジェクトを扱う事に特化して、
それ以外の応用が効きづらいので、検索フォームなど、
モデルオブジェクトと関連しない(データベースに保存しない)様な
フォームであれば、form_tagの方が適しています。

データベースへデータを保存・更新する場合は、form_for
データベースの検索を行いたい場合は、form_tag

という様に使い分ければ良いでしょう。

以上、でもこれ、form_withだったら、
どっちの使い方も出来るんですよね・・・それは次回。
(そしてRails 5.1から、form_forとform_tagは、
form_withに統合される・・・)