+1

create multiple object with Nested attributes

Nested attributes là gì?#

Nested attrbutes là một kỹ thuật xử lý params mới được tích hợp từ phiên bản 4.0 của framework Ruby on Rails cung cấp một công cụ khá mạnh mẽ và thuận lợi cho developer làm việc với form.

Tại sao sử dụng Nested?

Nếu chưa có sự xuất hiện của Nested attributes developer khi thực hiện các thao tác liên quan tới đăng ký, update luôn phải xử lý params với những câu lệnh đơn thuần mặc dù nhận được sự tùy biến nhưng đối với những form lớn hoặc mối quan hệ phức tạp thì thật sự không phải là giải pháp quá tốt. Controller nặng nề không giữ được sự nhẹ nhàng cần có sẽ khiến cho hệ thống ì ạch và khó khăn trong việc bảo trì.

Nested sẽ gói gọn tất cả những thao tác phức tạp đó trong bằng một vài cú pháp đơn giản, sáng sủa công việc của developer chỉ là khai báo, sử dụng thêm chút sáng tạo sẽ mang lại hiệu quả cao.

Sử dụng Nested với form_for, field_for#

Chuẩn bị##

Bắt đầu với new project.###

rails new demo-nested

Create model:###

rails g model hotel

rails g model room_categories

app/model/hotel.rb##

class Hotel < ActiveRecord::Base
  has_many :room_categories, dependent: :destroy
  validates :name, presence: true
end

app/model/room_category.rb##

class RoomCategory < ActiveRecord::Base
  belongs_to :hotel
  validates :name, presence: true
end

1. Create object không có liên kết.##

app/controller/hotel_controller.rb##

def new
  @hotel = Hotel.new
end

def create
  hotel = Hotel.create hotel_params
end

private
def hotel_params
  params.require(:hotel).permit :name
end

app/views/hotel/new.html.erb

<% form_for @hotel do |f| %>
  <div class="field">
    <%= f.label :name %><br>
    <%= f.text_field :name %>
    <%= f.submit %>
  </div>
<% end %>

2. Create object có liên kết với field_for.##

Giả dụ sau khi muốn tạo hotel cần tạo luôn 2 room categories cho hotel đó khai báo thêm như sau:

app/controller/hotel_controller.rb##

def new
  @hotel = Hotel.new
  @hotel.room_categories.build
end

def create
  hotel = Hotel.create hotel_params
end

private
def hotel_params
  params.require(:hotel).permit(:name, room_categories_attributes: [ :id, :name ])
end

app/views/hotel/new.html.erb

<% form_for @hotel do |f| %>
  <div class="field">
    <%= f.label :name %><br>
    <%= f.text_field :name %>
  </div>
  <h2>Room Categories</h2>
  <%= f.fields_for :room_categories do |room_category| %>
    <div class="room_category_fields">
      <div class="field">
        <%= room_category.label :name %><br>
        <%= room_category.text_field :name %>
      </div>
    </div>
  <% end %>
  <%= f.submit %>
<% end %>

app/model/hotel.rb##

class Hotel < ActiveRecord::Base
  has_many :room_categories, dependent: :destroy
  accepts_nested_attributes_for :room_categories
end

Sử dụng Nested với form_tag#

Câu hỏi đặt ra là trong trường hợp muốn tạo multiple hotel thì có sử dụng nested được không? Câu trả lời là có tuy nhiên cần tùy biến một chút.

  • Sử dụng form_tag thay cho form_for

<%= form_tag hotels_path do |f| %>
  <div class="field">
    <%= text_field_tag name: "hotels[][name]" %>
    <%= text_field_tag name: "hotels[][name]" %>
  </div>
<% end %>
  • Tùy biến trong controller permit với một mảng hotel.##

private
def hotel_params
  params.permit(hotels: name)[:hotels]
end

Kết luận#

Bài viết chỉ đề cập tới đăng ký với action update thì sử dụng nested tương tự. Controller ngắn gọn và rõ dàng dễ dàng lập trình và bảo trì. Rất mong nhận được đóng góp ý kiến từ các bạn.

Chúc các bạn thành công!!!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí