12/08/2018, 14:32
Rails Nested Forms using jQuery and SimpleForm
Chúng ta có 3 model: Stock model: cổ phiếu trên thị trường chứng khoáng. Portfolio model: Danh mục đầu tư.(Danh mục đầu tư chứa nhiều tài sản) Assets model: Mỗi tài sản có nhiều cổ phiếu. class Stock < ActiveRecord::Base has_many :assets end class Portfolio < ActiveRecord::Base ...
Chúng ta có 3 model:
- Stock model: cổ phiếu trên thị trường chứng khoáng.
- Portfolio model: Danh mục đầu tư.(Danh mục đầu tư chứa nhiều tài sản)
- Assets model: Mỗi tài sản có nhiều cổ phiếu.
class Stock < ActiveRecord::Base has_many :assets end class Portfolio < ActiveRecord::Base has_many :assets end class Asset < ActiveRecord::Base belongs_to :stock belongs_to :portfolio end
- models/portfolio.rb
class Portfolio < ActiveRecord::Base belongs_to :user has_many :assets attr_accessible :title, :assets_attributes accepts_nested_attributes_for :assets, allow_destroy: true end
- controllers/portfolios_controller.rb
class PortfoliosController < ApplicationController def new @portfolio = Portfolio.new @portfolio.assets.build end def edit @portfolio = current_user.portfolios.find params[:id] @portfolio.assets.build end end
- Giao diện cho nested attribute sẽ như sau:
- views/portfolios/_form.html.erb
<%= simple_form_for @portfolio do |f| %> <%= f.input :title, label: 'Portfolio Title' %> <%= f.simple_fields_for :assets do |assets_form| %> <%= assets_form.association :stock %> <%= assets_form.input :amount, :input_html => { min: 0} %> <% end %> <%= f.submit %> <% end %>
- Đến đây, nếu bạn load form thì nó có thể làm việc tốt. Thế nhưng bạn chỉ có thể tạo một asset form cho một portfolio form. Vì thế, chúng ta sẽ sử dụng jquery để cho người dùng có thể thêm bao nhiêu assets tùy thích.
- Ở đây, chúng ta sẽ đánh dấu các asset form để jquery có thể tìm thấy một cách dễ dàng. Chúng ta sẽ thêm class cho asset form và thêm button "Add Another Asset".
- views/portfolios/_form.html.erb
<%= simple_form_for @portfolio do |f| %> <%= f.input :title, label: 'Portfolio Title' %> <%= f.simple_fields_for :assets do |assets_form| %> < div = "duplicatable_nested_form"> <%= assets_form.association :stock %> <%= assets_form.input :amount, :input_html => { min: 0 } %> </div> <% end %> <%= link_to 'Add Another Asset', ', class: 'duplicate_nested_form' %> <%= f.submit %> <% end %>
- assets/javascripts/nested_forms.js
$(document).ready(function() { if $('.duplicatable_nested_form').length > 0 { nestedForm = $('.duplicatable_nested_form').last().clone(); //Tạo một bản sao của asset form } // Bắt sự kiện click button "Add Another Asset" $(document).on('click', '.duplicate_nested_form', function(e){ e.preventDefault(); // Chặn hoạt động thẻ a lastNestedForm = $('.duplicatable_nested_form').last(); // Lấy ra asset form cuối cùng newNestedForm = $(nestedForm).clone(); formsOnPage = $('.duplicatable_nested_form').length; // Lấy số lượng asset form // Thay đổi label $(newNestedForm).find('label').each(function(){ oldLabel = $(this).attr('for'); newLabel = oldLabel.replace(new RegExp(/_[0-9]+_/), "_#{formsOnPage}_"); $(this).attr ('for', newLabel); }); // Thay đổi id, name $(newNestedForm).find('select, input').each (function(){ oldId = $(this).attr('id'); newId = oldId.replace(new RegExp(/_[0-9]+_/), "_#{formsOnPage}_"); $(this).attr('id', newId); oldName = $(this).attr('name'); newName = oldName.replace(new RegExp(/[[0-9]+]/), "[#{formsOnPage}]"); $(this).attr('name', newName); }); $( newNestedForm ).insertAfter( lastNestedForm); // Thêm asset form mới }); })
- Thêm nút để bắt sự kiện xóa asset form *views/portfolios/_form.html.erb
<%= simple_form_for @portfolio do |f| %> <%= f.input :title, label: 'Portfolio Title' %> <%= f.simple_fields_for :assets do |assets_form| %> < div = "duplicatable_nested_form"> <%= assets_form.association :stock %> <%= assets_form.input :amount, :input_html => { min: 0 } %> <%= link_to 'Remove', ', :remote => true, :class => 'destroy_duplicate_nested_form' %> </div> <% end %> <%= link_to 'Add Another Asset', ', class: 'duplicate_nested_form' %> <%= f.submit %> <% end %>
- assets/javascripts/nested_forms.js.coffee
// Bắt sự kiện click button "remove" $(document).on('click', '.destroy_duplicate_nested_form', function(){ $(this).closest('.duplicatable_nested_form').slideUp().remove(); )};
- Nested attributes là một công nghệ mạnh mẽ để phát triển nhanh các forms phức tạp. Và có rất nhiều cách để có thể tận dụng tối đa những gì mà Nested attributes mang lại. Nhưng tôi nghĩ sử dụng jquery sẽ mang lại hiệu quả hơn cho nhưng người mới làm quen với ruby on rails.
Tham khảo: http://davidlesches.com/blog/rails-nested-forms-using-jquery-and-simpleform