+2

Trong bài viết này, chúng ta sẽ hoàn thiện 1 complex Rails 5 form. Cụ thể, chúng ta sẽ tìm hiểu cách cấu hình form, controller, và các files view để làm việc với nested attributes.

Bắt đầu với form tạo một item mới (ở đây là một portfolio) có dạng như sau:

Chúng ta có một tiêu đề, phụ đề và nội dung. Tuy nhiên, ta mong muốn khả năng lưu trữ thuộc tính của bản ghi này thông qua bản ghi khác cùng một lúc, ngay trên cùng 1 form. Điều này có nghĩa là chúng ta sẽ làm việc với nhiều models cùng một lúc. Để thực hiện được điều này, chúng ta cần thực hiện ở thay đổi ở 3 nơi.

Thay đổi trong Controller

Điều đầu tiên chúng ta cần làm là cập nhật controller. Ở trong portfolios_controller.rb, chúng ta cần cập nhật action new.

def new
  @portfolio_item = Portfolio.new
end

Hiện tại, đoạn code mình đưa vào sẽ là hard code.

def new
  @portfolio_item = Portfolio.new
  3.times { @portfolio_item.technologies.build }
end

Bằng việc sử dụng method .build đoạn code này về cơ bản sẽ khởi tạo 3 đối tượng portfolio_items với technologies. Nói cách khác, với một portfolio_items, chúng ta sẽ tạo ra 3 loại technologies để sử dụng trực tiếp trên form.

Việc tiếp theo chúng ta cần làm là khiến các thuộc tính của form có sẵn cho strong parameters. Hiện tại trong method create, chúng ta đã có các strong parameters tương ứng với tiêu đề, phụ đề và body. Chúng ta cần đưa vào thuộc tính mới cho technologies.

 @portfolio_item = Portfolio.new(params.require(:portfolio).permit(:title, :subtitle, :body, technologies_attributes: [:name]))

Chú ý rằng điều này trông rất giống với những gì chúng ta làm trong console, khi chúng ta truyền vào một mảng các giá trị cho technologies_attributes. Mảng này chỉ đơn giản chứa một thuộc tính duy nhất của tên. Chúng ta cũng có thể thêm các thuộc tính khác vào nếu cần thiết. Với đoạn code này, chúng ta đang cho Rails biết nếu có bất cứ dữ liệu gì đến đặc trưng cho technology_attributes và hoàn toàn có thể đưa vào database.

Đó là tất cả những gì chúng ta cần làm đối với controller.

Thay đổi trong View

Tiếp theo, chúng ta cần thay đổi form trong app/views/portfolios/new.html.erb

<h1>Create a new Portfolio Item</h1>

<%= form_for(@portfolio_item) do |f| %>
  <div class="field">
    <%= f.label :title %>
    <%= f.text_field :title %>
  </div>

  <div class="field">
    <%= f.label :subtitle %>
    <%= f.text_field :subtitle %>
  </div>

  <div class="field">
    <%= f.label :body %>
    <%= f.text_area :body %>
  </div>

  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

Ngay dưới form field cho body, chúng ta sẽ thêm vào thẻ <ul> chưa các thẻ <li>

<div class="field">
    <%= f.label :body %>
    <%= f.text_area :body %>
</div>
    <ul>
        <li>
        </li>
    </ul>

Dựa trên cách thức Rails mô tả nested attributes, chúng ta cần có 1 form nằm trong form

Ở trên cùng của view file chúng ta có <%= form_for(@portfolio_item) do |f| %> là form for ứng với portfolio_item, tuy nhiên chúng ta cần thêm 1 form for trong đó ứng với technology_attributes.

 <ul>
    <%= f.fields_for :technologies do |technology_form| %>
      <li></li>
    <% end %>
  </ul>

Nếu bạn đang tự hỏi làm thế nào các kết nối được thiết lập và làm sao để form biết cần truy cập vào đâu, chúng ta cần xem lại portfolio model. Trong portfolio.rb chúng ta có đoạn code:

accept_nested_attributes_for :technologies

Do đó chúng ta dùng technologies đó và đó là cách mọi thứ kết nối

Tiếp đến chúng ta xây dựng item bằng cách nhúng vào các đoạn code ruby

<ul>
    <%= f.fields_for :technologies do |technology_form| %>
      <li>
        <%= technology_form.label :name %>
        <%= technology_form.text_field :name %>
      </li>
    <% end %>
  </ul>

Kiểm tra đoạn code

Thử lại nào. Save code, refresh trình duyệt. Voila!

Lưu ý là những thay đổi vừa rồi chỉ áp dụng cho tạo mới, vì chúng ta mới chỉ thay đổi cho action new

Sau khi submit, phương thức create sẽ chuyển chúng ta tới trang portifolios, điều đó cho thấy rằng đoạn code đã chạy. Tuy nhiên ở trang portfolios chusgn ta vẫn chưa thể thấy các technologies vì chưa đưa vào đoạn code hiển thị. Tuy nhiên để kiểm tra đoạn code có chạy như mong muốn hay không chúng ta có thể kiểm tra ở Terminal:

Tuy nhiên, những dữ liệu này không có ích cho lắm nếu không thể view được trên trình duyệt. Do đó chúng ta cần tùy chỉnh lại file /portfolio/show.html.erb

<%= image_tag @portfolio_item.main_image %>

<h1><%= @portfolio_item.title %></h1>

<em><%= @portfolio_item.subtitle %></em>

<p><%= @portfolio_item.body %></p>

<% @portfolio_item.technologies.each do |t| %>
<p><%= t.name %></p>
<% end %>

Lưu code và refresh trình duyệt và cảm nhận thành quả:

Have technical problem? Ask on Viblo »

Comments

Login to comment
+2