Rails 5.1 form_with
Bài đăng này đã không được cập nhật trong 6 năm
form_tag
và form_for
đã "hơi cũ" (soft deprecated) và chúng sẽ được thay thế bởi form_with trong tương lai. Nếu bạn muốn biết thêm về form_with
, bạn có thể check thông tin về nó tại issue #25197 này, kiểm tra pull request implement helper này, và thử với một vài test project.
Ở bài viết này, mình sẽ giới thiệu sự khác nhau giữa 3 loại helper trên với một vài ví dụ cụ thể.
One syntax to rule them all
Trước kia, khi bạn muốn tạo một form, nhưng bạn lại không có model nào cụ thể, bạn có thể dùng form_tag
<%= form_tag users_path do %>
<%= text_field_tag :email %>
<%= submit_tag %>
<% end %>
Khi bạn taọ một form đại diện cho việc tạo mới hay update một model, bạn dùng form_for
<%= form_for @user do |form| %>
<%= form.text_field :email %>
<%= form.submit %>
<% end %>
Như bạn có thể thấy, chúng ta có thể dùng các builder field helper để tạo ra các trường trong form nhưng chúng ta ko thể dùng nó với form_tag
. Vì vậy cú pháp của hai kiểu viết form (cho model và không cho model) này là khác nhau.
Đối với form_with
thì lại khác, vì chúng ra sử dụng form builder hầu hết trong ứng dụng Rails app của mình, nên việc sử dụng form_with là rất tiện lợi và tránh được sai cú pháp đối với hai dạng build form.
form_with
khi không có model:
<%= form_with url: users_path do |form| %>
<%= form.text_field :email %>
<%= form.submit %>
<% end %>
form_with
khi có model:
<%= form_with model: @user do |form| %>
<%= form.text_field :email %>
<%= form.submit %>
<% end %>
Khi bạn truyền vào tham số model thì scope và url được tự động sinh ra từ object truyền vào đó. Điều này thì tương tự với form_for
Automatic ids and classes are gone
form_tag
và form_for
tự động sinh ra id cho các field ở trong form. form_for
làm vậy khi chúng ta chỉ cần khai báo:
<%= form_for User.new do |form| %>
<%= form.text_field :email %>
<% end %>
Nó sẽ tự sinh ra
<form class="new_user" id="new_user" action="/users" ...>
...
<input type="text" name="user[email]" id="user_email" />
</form>
Ở Rails 5.1 thì đối với form_with
, bạn phải tự định nghĩa ra id
và class
:
<%= form_with model: @user do |form| %>
<%= form.text_field :name %>
<%= form.text_field :email, id: :email, class: :email %>
<% end %>
Sẽ sinh ra:
<form action="/users" ...>
...
<input type="text" name="user[name]" />
<input id="email" class="email" type="text" name="user[email]" />
</form>
Đừng quên định nghĩa id
cho form fields nếu bạn muốn các labels hoạt động.
<%= form_with model: @user do |form| %>
<%= form.label :name %>
<%= form.text_field :name, id: :user_name %>
<% end %>
Từ Rails 5.2 thì các id sẽ được tự động sinh ra, vì thế không phải tự định nghĩa bằng tay nữa
Form id and class attributes aren’t wrapped anymore
Trước kia, khi muốn định nghĩa class
và id
cho thẻ form, bạn phải gói chúng trong tham số html
:
<%= form_for @user, html: { id: :custom_id, class: :custom_class } do |form| %>
<% end %>
Với form_with
, nó nhận định nghĩa này là tham số hash đầu vào và không cần bao đóng trong cặp { }
:
<%= form_with model: @user, id: :custom_id, class: :custom_class do |form| %>
<% end %>
Form fields không cần thiết phải tương ứng với model attributes
Với form_for
và bạn muốn khai báo thêm trường ngoài model trong form:
<%= form_for @user do |form| %>
<%= form.text_field :email %>
<%= check_box_tag :send_welcome_email %>
<% end %>
Với form_with
, trường không cần tương ứng với thuộc tính của model:
<%= form_with model: @user, local: true do |form| %>
<%= form.text_field :email %>
<%= form.check_box :send_welcome_email %>
<%= form.submit %>
<% end %>
Nhưng send_welcome_email
khi đó sẽ bị scoped trong user trong tham số params
của controller:
params[:user][:send_welcome_email]
All forms are remote by default
Đây là sự thay đổi thú vị nhất của form_with
. Tất cá các form được sinh ra từ form_with
sẽ mặc định submit XHR request. Không cần khai báo remote: true
như với form_tag
và form_for
. Vì vậy, nếu bạn vẫn muốn tạo form với html request thì phải disable remote form bằng cách khai báo local: true
<%= form_with model: @user, local: true %>
<% end %>
Trên đây là những điểm khác biệt khi sử dụng các loại form helper trong Rails, hai phương thức form_for
và form_tag
sẽ sớm deprecated trong tương lai và được thay thế bởi form_with
, vậy chúng ta nên thực hành và tìm hiểu về nó trước khi sử dụng cho các project sau này của mình. Happy coding !!!
Tham khảo
All rights reserved