create multiple object with Nested attributes
Bài đăng này đã không được cập nhật trong 9 năm
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