585
551

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2018-07-01

はじめに

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

585
551
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
585
551

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?