Form_with trong Rails 5.1 với form_for và form_tag
form_for và form_tag đã rất quen thuộc trong các phiên bản Rails, nhưng chúng sẽ được thay thế bởi form_with trong tương lai (rails 5.1). Dưới đây giới thiệu về sự khac nhau giữa form_for, form_tag và form_with với các ví dụ đơn giản. Một cú pháp cho tất cả Trước đây, khi bạn muốn tạo một form ...
form_for và form_tag đã rất quen thuộc trong các phiên bản Rails, nhưng chúng sẽ được thay thế bởi form_with trong tương lai (rails 5.1). Dưới đây giới thiệu về sự khac nhau giữa form_for, form_tag và form_with với các ví dụ đơn giản.
Một cú pháp cho tất cả Trước đây, khi bạn muốn tạo một form nhưng không có đối tượng cho nó, bạn sử dụng form_tag:
<%= form_tag users_path do %> <%= text_field_tag :email %> <%= submit_tag %> <% end %>
Khi có một đối tượng, bạn sử dụng form_for:
<%= form_for @user do |form| %> <%= form.text_field :email %> <%= form.submit %> <% end %>
Như bạn đã thấy, chúng ta sử dụngform builder field helper với form_for nhưng lại không sử dụng với form_tag, vì vậy cú pháp của cả 2 forms này là khác nhau. Nhưng với form_with, chúng ta sử dụng form buildercho tất cả các field. form_with khi không có đối tượng:
<%= form_with url: users_path do |form| %> <%= form.text_field :email %> <%= form.submit %> <% end %>
và khi có đối tượng:
<%= form_with model: @user do |form| %> <%= form.text_field :email %> <%= form.submit %> <% end %>
Khi bạn thêm các đối số cho đối tượng, các scope và url sẽ tự động điều hướng từ đó, nó hoạt động giống như form_for.
Không tự động thêm id và class cho thẻ form và form field form_tag và form_for tự động tạo id cho các trường của form, form_for còn thêm cả cho thẻ form:
<%= form_for User.new do |form| %> <%= form.text_field :email %> <% end %>
sẽ tạo ra:
<form class="new_user" id="new_user" action="/users" ...> ... <input type="text" name="user[email]" id="user_email" /> </form>
Với form_with, bạn phải tự thêm các id và class bằng tay:
<%= form_with model: @user do |form| %> <%= form.text_field :name %> <%= form.text_field :email, id: :email, class: :email %> <% end %>
Tạo ra:
<form action="/users" ...> ... <input type="text" name="user[name]" /> <input id="email" class="email" type="text" name="user[email]" /> </form>
Đừng quên thêm các id cho các trường của form nếu bạn muốn các label có thể hoạt động:
<%= form_with model: @user do |form| %> <%= form.label :name %> <%= form.text_field :name, id: :user_name %> <% end %>
Thuộc tính id và class của form không được đóng gói nữa Trước đây:
<%= form_for @user, html: { id: :custom_id, class: :custom_class } do |form| %> <% end %>
Mới:
<%= form_with model: @user, id: :custom_id, class: :custom_class do |form| %> <% end %>
Các trường của form không cần phải tương ứng với các thuộc tính của model Trước đây:
<%= form_for @user do |form| %> <%= form.text_field :email %> <%= check_box_tag :send_welcome_email %> <% end %>
Mới:
<%= form_with model: @user, local: true do |form| %> <%= form.text_field :email %> <%= form.check_box :send_welcome_email %> <%= form.submit %> <% end %>
Chú ý rằng send_welcome_email sẽ được gửi tới controller dưới dạng params params[:user][:send_welcome_email] vì vậy, bạn vẫn có thể sử dụng check_box_tag thay vì form.check_box nếu bạn cần.
Tất cả các form đều mặc định ở chế độ remote Tất cả các form được tạo bởi form_with sẽ được submit mặc định bởi request XHR(Ajax). Bạn không cần thêm remote: true như khi sử dụng form_for và form_tag và chỉ cần tạo thêm một template respond Javascript để nó có thể hoạt động. Nếu bạn không muốn sử dụng remote cho form, bạn có thể thêm local: true như sau:
<%= form_with model: @user, local: true %> <% end %>
Trên đây giới thiệu một vài sự khác nhau của form_for, form_tag và form_with, bạn có thể đọc thêm về from_with tại: http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-form_with