Rails 初心者的學習筆記:form_for和form_with的比較

Apple Chen
5 min readSep 1, 2019

--

Rails 5.1釋出後,其中一項令人關注的重點便是form_with。根據DHH大神的說法,之所以會推出這個新方法,是因為form_tag和form_for這兩個相似的介面所提供的功能,有很多是重複的,需要加以整合;再加上有些helpler的效能不佳,他想藉此機會改善,因此便有了form_with這個新方法。

form_with做了哪些改變?

1.表單預設使用remote傳送
由form_with產生的表單,預設以Ajax傳送,所以不像form_tag、form_for需要設定remote: true。如果要更改預設值,則需輸入local: true。

<%= form_with model: @post, local: true do |form| %>

2.可用scope加上前綴
scope是一個新的option,可在input field name加上前綴。要傳送參數群組給controller的時候特別好用。

<%= 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屬性
例如想要增加一個checkbox讓作者透過email提醒讀者,但checkbox並不對應model屬性,此時可以用FormBuilder實體來增加checkbox:

<%= form_with model: @post do |form| %>
<%= form.text_field :author %>
<%= form.check_box :notify_readers %>
<%= form.submit “Create” %>
<% end %>
<form action=”/posts” accept-charset=”UTF-8" data-remote=”true” method=”post”>
<input name=”utf8" type=”hidden” value=”✓”>
<input type=”hidden” name=”authenticity_token” value=”…”>
<input type=”text” name=”post[author]”>
<input name=”post[notify_readers]” type=”hidden” value=”0">
<input type=”checkbox” value=”1" name=”post[notify_readers]”>
<input type=”submit” name=”commit” value=”Create” data-disable-with=”Create”>
</form>

4.不會自動生成id和class
在Rails 5.1版本的form_with,id和class需由開發者自行指定;但在Rails 5.2以後,則又改回和form_tag、form_for一樣,會自動附加id和class屬性,不需由開發者指定。

<%= 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>

5.「:class」「:id」「:data」從HTML屬性中獨立出來
在form_tag、form_for使用HTML中的class、id、data屬性時,需要用花括號將這些屬性包起來:

<%= 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結合了form_tag和form_for的特點,且修改了一些作法,讓操作時更有彈性,想必之後可以漸漸取代form_tag和form_for。

這篇文章只是copy+paste+翻譯的集合體(掩面),有機會實作的話,應該可以更理解form_with的用法。

參考資料:

form_with — Building HTML forms in Rails 5.1

form_withについて解説

[Rails 5.1] ‘form_with’ APIドキュメント完全翻訳

--

--