Rails在建立表單的時候,form_for 跟 form_with 有什麼不同?

Anne Ju
7 min readSep 1, 2019

--

form_with是…?

在Rails 5.1之前,有兩種表格,一個是 form_tag,一個是 form_for,兩者有些微差異。在以前,如果表格的對象有Model,則用form_for,Rails會利用Model的屬性來新增或更新Model所產生的資料;若沒有Model實體時,form_tag 則使用傳入連結的action進行表單傳送。Rails 5.1出來後,將兩者結合,成為 form_with

不管是用url或是model,都可以用form_with製作表格

使用form_with製作表格的對象”沒有Model”時:

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

看看HTML:

<form action="/owners/new" data-remote="true" method="post">
<input name="utf8" type="hidden" value="&#x2713;" />
<input type="hidden" name="authenticity_token" value="...." /> <input type="text" name="name" id="name" />
<input type="submit" name="commit" value="Save " data-disable-with="Save " />
</form>

使用form_with製作表格的對象”有Model”時:

<%= form_with model: Owner.new do |form| %>
<%= form.text_field :email %>
<%= form.submit %>
<% end %>

看看HTML:

<form action="/owners" accept-charset="UTF-8" data-remote="true" method="post">
<input name="utf8" type="hidden" value="&#x2713;" />
<input type="hidden" name="authenticity_token" value="..." /> <input type="text" name="owner[name]" id="owner_name" />
<input type="submit" name="commit" value="Create Owner" data-disable-with="Create Owner" />
</form>

由此可見,兩者幾乎是一樣的,差別只在於我們是告訴form_with 我們要用Model或是用url建立表格。

使用form_with時,建立時就已經預設了remote: true

我們先用form_with建立一個表格:

<%= form_with model: Message.new do |form| %>
<%= form.text_field :subject %>
<% end %>

打開HTML來看:

<form action="/messages" method="post" data-remote="true">
<input type="text" name="subject">
</form>

可以看到data-remote="true"。有了這個屬性之後,表單會透過 Ajax 提交,而不是瀏覽器平常的提交機制。如果不要設定Ajax提交,則要另訂 local: true

使用form_with時,Model不一定需要設定相對應的屬性

使用form_for時:

<%= form_for @owner do |form| %>
<%= form.text_field :email %>
<%= check_box_tag :send_welcome_email %> ← 這一行
<%= form.submit %>
<% end %>

使用form_with時:

<%= form_with model: @owner do |form| %>
<%= form.text_field :email %>
<%= form.check_box :send_welcome_email %> ← 這一行
<%= form.submit %>
<% end %>

form_with新增的HTML:

<input name="owner[send_welcome_email]" type="hidden" value="0" /><input type="checkbox" value="1" name="owner[send_welcome_email]" id="owner_send_welcome_email" />

雖然Owner的Model中沒有這個屬性,你還是可以用FormBuilder寫出統一性的指令,而且這個資訊依然可以用owner[send_welcome_email]收集。

使用form_with時,HTML設定不用再需要使用{ }包起來

使用form_for或是form_tag時,若要設定如id、class,要如此寫:

<%= form_for @post, html: { id: “custom-id”, class: “custom-class” } do |form| %>

使用form_with可以不用再用花括弧:

<%= form_with model: @post, id: “custom-id”, class: “custom-class” do |form| %>

最後再記錄一下使用form_with的寫法:

  1. 指定url時:
<%= form_with url: posts_path do |form| %>
<%= form.text_field :title %>
<% end %>

<%# ↓生成されるタグ %>

<form action="/posts" method="post" data-remote="true">
<input type="text" name="title">
</form>

2. 用scope帶入Prefix時:

<%= form_with scope: :post, url: posts_path do |form| %>
<%= form.text_field :title %>
<% end %>

<%# ↓生成されるタグ %>

<form action="/posts" method="post" data-remote="true">
<input type="text" name="post[title]">
</form>

3. 指定Model時:

<%= form_with model: Post.new do |form| %>
<%= form.text_field :title %>
<% end %>
or<%= form_with model: @post do |form| %>
<%= form.text_field :title %>
<% end %>
<%# ↓生成されるタグ %>

<form action="/posts" method="post" data-remote="true">
<input type="text" name="post[title]">
</form>

以上範例引用Ruby on Rails 5.1 リリースノート

參考資料:

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

Rails5.1で出て来たform_withとは

USING FORM_WITH VS FORM_FOR VS FORM_TAG

在 Rails 使用 JavaScript

form_with — Building HTML forms in Rails 5.1

--

--