+6

Giới thiệu về form_for trong rails

form_for là phương thức tạo ra một form cho phép người dùng có thể create hoặc update các thuộc tính của một model object cụ thể. Phương thức này có thể được sử dụng trong nhiều cách khác nhau. Đối với một model object chung, một form có thể được tạo ra bằng cách truyền qua form_for một string hoặc một symbol đại diện cho object mà chúng ta quan tâm đến:

<%= form_for :person do |f| %>
  First name: <%= f.text_field :first_name %><br />
  Last name : <%= f.text_field :last_name %><br />
  Biography : <%= f.text_area :biography %><br />
  Admin?    : <%= f.check_box :admin %><br />
  <%= f.submit %>
<% end %>

biến f là một FormBuilder object kết hợp với hiểu biết về model object đại diện bởi :person truyền qua form_for. Các phương thức được định nghĩa trong FormBuilder được sử dụng để tạo ra các trường rằng buộc với model này. VÍ dụ:

<%= f.text_field :first_name %>

sẽ được mở rộng:

<%= text_field :person, :first_name %>

Kết quả là thẻ <input> HTML có thuộc tính name là person[first_name]. Điều này có nghĩa là khi form được submitted, giá trị được nhập bởi người dùng sẽ có sẵn trong controller dưới dạng params[:person][:first_name]. Với các trường được tạo bằng cách sử dụng FormBuilder, khi thay thế symbol :person bằng một instance variable @person, giá trị mặc định của các trường trong form sẽ hiển thị tương ứng với giá trị của các thuộc tính của @person. Các đối số tùy chọn của form_for: * :url * :namespace * :method * :authenticity_token * :remote * :enforce_utf8 * :html Chú ý ràng form_for không tạo ra một phạm vi độc quyền. Nó vẫn có thể sử dụng cả hai phương thức FormHelper và FormTagHelper một cách độc lập. ví dụ:

<%= form_for :person do |f| %>
  First name: <%= f.text_field :first_name %>
  Last name : <%= f.text_field :last_name %>
  Biography : <%= text_area :person, :biography %>
  Admin?    : <%= check_box_tag "person[admin]", "1", @person.company.admin? %>
  <%= f.submit %>
<% end %>

form_for với một model object

Trong ví dụ ở trên, đối tượng được tạo hoặc chỉnh sửa đại diện bởi một symbol truyền qua form_for, lưu ý là một string cũng có thể được sử dụng tương đương. Tuy nhiên cũng có thể sử dụng bản thân một model object đến form_for. Ví dụ, nếu @post là một bản ghi đã tồn tại mà bạn muốn edit, bạn có thể tạo ra một form như sau:

<%= form_for @post do |f| %>
  ...
<% end %>

Nó hoạt đông gần giống như cách đã nêu ở trên, với một vài ngoại lệ nhỏ. Đầu tiên, tiền tố được sử dụng để đặt tên cho các phần tử input trong form là thực sự bắt nguồn từ lớp của đối tượng. Tuy nhiên nó có thể ghi đè sử dụng option :as, ví dụ:

<%= form_for(@person, as: :client) do |f| %>
  ...
<% end %>

kết quả là params[:client]. Thứ hai là, giá trị của các trường được hiển thị khi form được hiển thị ban đầu được lấy ra từ các thuộc tính của đối tượng được truyền vào form_for, bất kể đối tượng là một instance variable. Ví dụ, nếu chúng ta có một local variable là post đại diện cho một bản ghi đã tồn tại,

<%= form_for post do |f| %>
  ...
<% end %>

sẽ tạo ra một form với các trường có trạng thái ban đầu phản ánh giá trị hiện tại của các thuộc tính của post.

Resource-oriented style

Trong các ví dụ vừa đưa ra, mặc dù không chỉ ra rõ ràng, chúng ta cũng cần sử dụng option :url để chỉ ra nơi mà form sẽ được gửi. Tuy nhiên đơn giản hơn nếu bản ghi được truyền qua form_for là một resource, tương ứng với một tập các RESTful routes. Trong trường hợp này Rails sẽ chỉ cần suy ra URL thích hợp từ bản thân bản ghi. Ví dụ:

<%= form_for @post do |f| %>
  ...
<% end %>

tương đương với:

<%= form_for @post, as: :post, url: post_path(@post), method: :patch, html: { class: "edit_post", id: "edit_post_45" } do |f| %>
  ...
<% end %>

Và cho một bản ghi mới:

<%= form_for(Post.new) do |f| %>
  ...
<% end %>

tương đương với:

<%= form_for @post, as: :post, url: posts_path, html: { class: "new_post", id: "new_post" } do |f| %>
  ...
<% end %>

Tuy nhiên bạn cũng có thể ghi đè các quy ước, như sau:

<%= form_for(@post, url: super_posts_path) do |f| %>
  ...
<% end %>

Bạn cũng có thể đặt định dạng câu trả lời như:

<%= form_for(@post, format: :json) do |f| %>
  ...
<% end %>

Đối với namespaced routes, như admin_post_url:

<%= form_for([:admin, @post]) do |f| %>
 ...
<% end %>

Nếu resource của bạn có các association được định nghĩa, ví dụ như bạn muốn thêm comments vào document trong đó các routes được thiết lập chính xác:

<%= form_for([@document, @comment]) do |f| %>
 ...
<% end %>

trường hợp @document = Document.find(params[:id]) và @comment = Comment.new.

Setting the method

Bạn có thể buộc form sử dụng toàn bộ các method hỗ trợ bởi HTTP bằng cách:

method: (:get|:post|:patch|:put|:delete)

Unobtrusive JavaScript

Chỉ ra:

remote: true

Tạo ra một form cho phép các trình điều khiển Unobtrusive JavaScript để sửa đổi hàng vi của nó. Các hành vi mặc định mong chờ là một XMLHttpRequest trong nền thay thế cho POST, nhưng hành vi cuối cùng là lựa chọn của trình điều khiển JavaScript. Ví dụ:

<%= form_for(@post, remote: true) do |f| %>
  ...
<% end %>

HTML được tạo ra là:

<form action='http://www.example.com' method='post' data-remote='true'>
  <input name='_method' type='hidden' value='patch' />
  ...
</form>

Setting HTML options

Bạn có thể thiết lập trực tiếp các dữ liệu thuộc tính bằng cách truyền một dữ liệu băm, nhưng tất cả các option khác của HTML phải được đặt trong khóa HTML. ví dụ:

<%= form_for(@post, data: { behavior: "autosave" }, html: { name: "go" }) do |f| %>
  ...
<% end %>

HTML được tạo ra là:

<form action='http://www.example.com' method='post' data-behavior='autosave' name='go'>
  <input name='_method' type='hidden' value='patch' />
  ...
</form>

Loại bỏ id model ẩn

form_for sẽ tự động thêm model id như là một trường ẩn ở trong form. Điều này được sử dụng để duy trì mối tương quan giữa dữ liệu form và model liên quan đến nó. Một số hệ thống ORM không sử dụng IDs trên các mô hình lồng nhau vì vậy trong trường hợp này bạn muốn vô hiệu hóa id ẩn. trong ví dụ model Post có nhiều Comment được lưu trữ trong một NoSQL database, do đó không có primary key cho comments. ví dụ:

<%= form_for(@post) do |f| %>
  <%= f.fields_for(:comments, include_id: false) do |cf| %>
    ...
  <% end %>
<% end %>

Customized form builders

Bạn cũng có thể xây dựng các form sử dụng một lớp FormBuilder tùy chỉnh. SubClass FormBuilder và ghi đè hoặc định nghĩa một số helpers, sau đó sử dụng custom builder của bạn. Ví dụ, bạn tạo ra một helper để tự động thêm label cho các trường trong form:

<%= form_for @person, url: { action: "create" }, builder: LabellingFormBuilder do |f| %>
  <%= f.text_field :first_name %>
  <%= f.text_field :last_name %>
  <%= f.text_area :biography %>
  <%= f.check_box :admin %>
  <%= f.submit %>
<% end %>

Trong trường hợp này, nếu bạn sử dụng:

<%= render f %>

Mẫu được hiển thị là people/_labelling_form và biến cục bộ tham chiếu đến form builder được gọi là labelling_form. Lớp FormBuilder tùy chỉnh được tự động sáp nhập với các tùy chọn của lời gọi fields_for lồng nhau, trừ khi nó được thiết lập rõ ràng. trong nhiều trường hợp, bạn có thể muốn bọc những điều trên bằng một helper khác, như sau:

def labelled_form_for(record_or_name_or_array, *args, &block)
  options = args.extract_options!
  form_for(record_or_name_or_array, *(args << options.merge(builder: LabellingFormBuilder)), &block)
end

Nếu bạn không cần đính kèm một form cho một model instance, hãy checkout FormTagHelper#form_tag.

Form to external resources

Khi bạn xây dựng các form cho external resources đôi khi bạn cần thiết lập một authenticity token hoặc chỉ cần render một form mà không cần nó, ví dụ khi bạn gửi dữ liệu đến cổng thanh toán số và kiểu của trường có thể bị hạn chế. Để thiết lập một authenticity token bạn cần thông qua một tham số :authenticity_token

<%= form_for @invoice, url: external_url, authenticity_token: 'external_token' do |f|
  ...
<% end %>

Nếu bạn không muốn một trường authenticity token được kết suất chỉ cần đặt tham số là false:

<%= form_for @invoice, url: external_url, authenticity_token: false do |f|
  ...
<% end %>

Như vậy mình đã trình bày xong nội dung và các thao tác cơ bản về form_for trong rails, cảm ơn các bạn đã theo dõi bài viết. Nguồn tham khảo: http://apidock.com/rails/ActionView/Helpers/FormHelper/form_for


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.