Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

はじめに

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

hmmrjn
社会人1年目でWebエンジニアやってます。
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
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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
ユーザーは見つかりませんでした