536
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

【Rails 5】(新) form_with と (旧) form_tag, form_for の違い

はじめに

form_tagform_for は Rails5.1で soft deprecated (非推奨) となり、
将来のRailsリリースで form_with に完全に置き換えられる予定です。
そこで、この記事では、form_tag, form_forform_with の違いについて触れていきたいと思います。

一人二役の構文

これまで、フォームを作りたいときで、関連するモデルがなかったときは form_tag を使ってきました。

<%= form_tag users_path do %>
  <%= text_field_tag :email %>
  <%= submit_tag %>
<% end %>

そして、モデルがあったときは form_for を使ってきました。

<%= form_for @user do |form| %>
  <%= form.text_field :email %>
  <%= form.submit %>
<% end %>

見ての通り、form_for ではフォームのビルドヘルパー(form.hoge)を使うのに対し、
form_tag では使いません。そのため、二つのフォームで構文が違っていました。

しかし、新しいform_with は違います。どちらの場合でもビルドヘルパーを使います。

関連するモデルがない form_with :

<%= form_with url: users_path do |form| %>
  <%= form.text_field :email %>
  <%= form.submit %>
<% end %>

関連するモデルがある form_with :

<%= form_with model: @user do |form| %>
  <%= form.text_field :email %>
  <%= form.submit %>
<% end %>

モデルを渡したときは、URLとスコープが自動推測されます。(これまでのform_for と同じ。)
URL: @userがDBに存在するときはupdateアクションに、ないときはcreateアクションに飛びます。
スコープ: params[:email]params[:user][:email] になります。

フォームフィールドはモデルの属性に対応しなくても大丈夫

Before:

<%= form_for @user do |form| %>
  <%= form.text_field :email %>
  <%= check_box_tag :send_welcome_email %> ← ここ
  <%= form.submit %>
<% end %>

After:

<%= form_with model: @user, local: true do |form| %>
  <%= form.text_field :email %>
  <%= form.check_box :send_welcome_email %> ← ここ
  <%= form.submit %>
<% end %>

なお、後方の例では、send_welcome_emailuserスコープに設定されます。

# コントローラにて
params[:user][:send_welcome_email]

したがって、場合によっては form.check_box ではなく、check_box_tag を今後も使うことがあると思います。

formタグのidとclass属性はhtml: { }で囲まなくても大丈夫

Before:

<%= form_for @user, html: { id: :custom_id, class: :custom_class } do |form| %>
<% end %>

After:

<%= form_with model: @user, id: :custom_id, class: :custom_class do |form| %>
<% end %>

リモートフォームがデフォルトとなります

form_with で生成されたフォームは、デフォルトで非同期通信のXHR(Ajax)リクエストで送信されます。
よって、form_tagform_for のように、remote: trueと指定する必要がありません。

これまでも、Turbolinksのおかげで、(ほとんど)すべてのGETリクエストはデフォルトでXHRリクエストになっていましたが、今回の form_with で、フォームでもXHRを使うようにRails公式が促しているような印象を受けました。ちなみに、JavaScriptのレスポンステンプレートを作れば、ページ全体のリフレッシュを無くすことができるので、これを機にフォームでもXHRを使い始めてはいかがでしょうか。

もし、リモートフォームを無効にした場合は local: true と指定します。

<%= form_with model: @user, local: true %>
<% end %>

idとclass属性の自動付与について (Rails5.2の変更)

Rails 5.1のform_with では、input要素などのフォームフィールドへのidとclass属性の自動付与が無効となっていて、すべて自分で指定する必要がありましたが、Rails 5.2以降では、form_tag と form_for のように、id属性を自動付与するようになったので、すべて自分で指定する必要はなくなりました。

<%= form_with User.new do |form| %>
  <%= form.text_field :email %>
<% end %>

Rails 5.1:

<form action="/users">
  <input type="text" name="user[email]" />
</form>

Rails 5.2:

<form class="new_user" id="new_user" action="/users">
  <input type="text" name="user[email]" id="user_email" />
</form>

最後に

これからは form_with を使うようにしましょう。
form_tagform_for はもう使わなくよいでしょう。(どうせ、いずれ消されますし。)

もしこの記事がみなさんの役に立てば幸いです。:muscle:

もっと深掘りをしたい方は、form_withのドキュメント(英語) をどうぞ。

参考

Rails 5.1's form_with vs. form_tag vs. form_for – Patrik on Rails

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
536
Help us understand the problem. What are the problem?