0

Nested form fields trong rails

Là một gem của rails giúp tạo ra form cho model cùng với quan hệ nested has_many Gem này sử dụng JQuery để tự động thêm vào xóa đi quan hệ nested

  • Làm việc với các quan hệ nested lồng nhau (có thể lên đến mức 4)
  • Làm việc cùng với form builders giống như simple_form
  • Yêu cầu ruby 1.9 trở lên

Cài đặt

Thêm dòng này vào Gemfile trong ứng dụng của bạn

gem "nested_form_fields"

và chạy lệnh

$ bundle

Trong file application.js của ứng dụng bạn thêm vào dòng sau để có thể sử dụng được file nested_form_fields.js.coffee //= require nested_form_fields

Sử dụng

Giả sử bạn có model User cùng với nested videos:

class User < ActiveRecord::Base
  has_many :videos
  accepts_nested_attributes_for :videos, allow_destroy: true
end

Sử dụng nested_fields_for hepler bên trong user form của bạn để thêm vào các videos

= form_for user do |f|
  = f.nested_fields_for :videos do |ff|
    = ff.text_field :video_title
    ..

Đường link để thêm và xóa các field là add_nested_fields_link and remove_nested_fields_link

= form_for user do |f|
  = f.nested_fields_for :videos do |ff|
    = ff.remove_nested_fields_link
    = ff.text_field :video_title
    ..
  = f.add_nested_fields_link :videos

Chú ý rằng remove_nested_fields_link được gọi bên trong nested_fields_for và add_nested_fields_link được gọi từ bên ngoài thông qua parent builder.

Sửa đổi link

Chúng ta có thể thay đổi tên link của remove_nested_fields_linkadd_nested_fields_link như thế này:

...
  ff.remove_nested_fields_link "Remove me"
  ...
f.add_nested_fields_link :videos, "Add another funtastic video"

Chúng ta có thể thêm class/addtributes vào remove_nested_fields_link and add_nested_fields_link giống như:

...
  ff.remove_nested_fields_link "Remove me", class: "btn btn-danger", role: "button"
  ...
f.add_nested_fields_link :videos, "Add another funtastic video", class: "btn btn-primary", role: "button"

Bạn có thể thêm vào một khối vào remove_nested_fields_link và the add_nested_fields_link như thể bạn dùng link_to

= ff.remove_nested_fields_link do
  Remove me %span.icon-trash

Bạn có thể thêm vào thuộc tính data-confirm vào remove_nested_fields_link nếu bạn muốn người dùng confirm bất kể khi nào họ muốn xóa một nested field:

= ff.remove_nested_fields_link "Remove me", data: {confirm: "Are you sure?"}

Custom Container

Bạn có thể định nghĩa một custom container để thêm vào trong nested forms bằng cách cung cấp một id thông qua thuộc tính data-insert-into của add_nested_fields_link:

f.add_nested_fields_link :videos, "Add another funtastic video", data: {insert_into: "<container_id>"}

Custom Fields Wrapper

Bạn có thể thay đổi kiểu của các phần tử wrapping trong nested fields sử dụng thuộc tính wrapper_tag:

= f.nested_fields_for :videos, wrapper_tag: :div do |ff|

Các phần tử wrapper mặc định là một fieldset. Để thêm phần tử legend vào fieldset thì sử dụng:

= f.nested_fields_for :videos, legend: "Video" do |ff|

Bạn có thể dùng wrapper_options để truyền vào một hash các lựa chọn, giống như bạn sử dụng phương thức content_tag

= f.nested_fields_for :videos, wrapper_options: {class: "row"} do |ff|

Parameter trong rails 4

Trong rails 4 để truyền về các params bạn phải khai báo {{ NESTED_MODEL }}_attributes trong controller. Nếu bạn muốn xóa các nested model bạn nên thêm vào :_destroy and :id. Ví dụ:

# app/views/users/_form.haml.erb
= form_for user do |f|
  = f.nested_fields_for :videos do |ff|
    = ff.remove_nested_fields_link
    = ff.text_field :video_title
    ..
  = f.add_nested_fields_link :videos
# app/controllers/users_controller
..
def user_params
    params.require(:user)   .permit(:name,:email,videos_attributes[:video_title,:_destroy,:id])
end

Sự kiện

Có 4 sự kiện javascript trước và sau khi thêm/xóa các field trong nested_form_fields tên là:

  • fields_adding
  • fields_added
  • fields_removing
  • fields_removed

Sự kiện fields_added and fields_removed được trigger trên phần tử khi đang được thêm hoặc xóa bỏ. Dễ dàng để thêm các listener khi mà có nhiều nested_form_fields trên những các trang tương tự nhau.

Ví dụ CoffeeScript:

# Listen on an element
initializeSortable -> ($el)
  $el.sortable(...)
  $el.on 'fields_added.nested_form_fields', (event, param) ->
    console.log event.target # The added field
    console.log $(this)      # $el

# Listen on document
$(document).on "fields_added.nested_form_fields", (event, param) ->
  switch param.object_class
    when "video"
      console.log "Video object added"
    else
      console.log "INFO: Fields were successfully added, callback not handled."

Bạn có thể truyền bất kỳ dữ liệu mở rộng nào trong sự kiện callback

# Trigger button click programmatically and pass an object `{hello: 'world'}`
$('.add_nested_fields_link').trigger('click', [{hello: "world"}])

# Listen for the event
$(document).on "fields_added.nested_form_fields", (event, param) ->
  console.log param.additional_data #=> {hello: "world"}

Tài liệu tham khảo

Bài viết này mình có tham khảo tại địa chỉ trang web sau, rất mong nhận được sự đóng góp ý kiến của các bạn để bài viết của mình có thể hoàn thiện hơn nữa

https://github.com/ncri/nested_form_fields


All Rights Reserved

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