Xóa Nhiều Record Đã Lựa Chọn Bởi Checkbox Trong Rails 4
Bài đăng này đã không được cập nhật trong 9 năm
Trong qúa trình phát triển ứng dụng web với Rails, mình gặp một vấn đề cần giải quyết đó là xóa đi một số records mà người dùng lựa chọn trong danh sách các records thông qua checkbox.
Có rất nhiều cách để làm việc này, dưới đây mình trình bày 2 cách đó là
- xóa thông thường không sử dụng ajax
- xóa sử dụng ajax
Trước tiên để tiện theo dõi mình lấy một ví dụ là:
Mình có một bảng danh sách các products được liệt kê theo dạng bảng và mỗi dòng có 1 nút chọn (checkbox) cho product đó.
Một button để submit xóa các products đã chọn.
Xóa không sử dụng ajax
Hiển thị dạng bảng như sau:
views/products/index.slim
= form_tag "", method: :delete, data: {confirm: "Are you sure?"}
table.table.table-striped.table-hover.table-bordered
thead
tr
th.text-center= t(".action")
th= t(".product_name")
th= t(".product_kind")
th= t(".jan_code")
tbody
- @products.each do |product|
tr
td.text-center= check_box_tag :product_ids, product.id, false,
class: "check-box-field"
td= product.name
td= product.product_kind
td= product.jan_code
= submit_tag "Xóa"
Tới đây mình sẽ có lựa chọn cho việc xóa các record đã checked.
- viết một hàm mới và tạo
collectioncho nó với phương thứcdelete - tạo một controller mới và cho nó là
singular resource
Với cách thứ nhất thì sẽ không theo RESTful có thể làm như sau
Trong products_controller.rb
def destroy_selected
if params[:product_ids]
Product.where(id: params[:product_ids]).destroy_all
end
redirect_to products_path
end
Trong routes.rb
resources :products do
collection do
delete :destroy_selected
end
end
Cấu hình routes như vậy cho mình đường dẫn destroy_selected_products_path trỏ tới hàm destroy_selected trên.
Sửa lại dòng sau trong products/index.slim
= form_tag "", method: :delete, data: {confirm: "Are you sure?"}
chuyển thành
= form_tag destroy_selected_products_path(product_ids: params[:product_ids]), method: :delete, data: {confirm: "Are you sure?"}
Như vậy khi submit thì sẽ xóa các lựa chọn records
Tuy nhiên để tuân thủ RESTful mình làm như sau
Tạo một controller mới tên là bulk_products
rails g controller bulk_products destroy
Hàm destroy trong controller này làm tương tự như destroy_selected ở phía trên.
Trong routes.rb cấu hình
scope :products do
resource :bulk_product
end
Cấu hình như vậy cho mình đường dẫn bulk_product_path với phương thức delete trỏ tới hàm destroy
Như vậy sửa lại dòng sau trong products/index.slim
= form_tag "", method: :delete, data: {confirm: "Are you sure?"}
Thành
= form_tag bulk_product_path(product_ids: params[:product_ids]), method: :delete, data: {confirm: "Are you sure?"}
Sử dụng ajax
Một số trường hợp mình không sử dụng cách thông thường như trên với form_tag, do vậy mình sử dụng ajax để làm việc này.
Về cơ bản thì vẫn là post một mảng các id của products đã chọn để xóa lên server.
Mình vẫn sử dụng controller là bulk_products ở phía trên. Hàm destroy sửa lại một chút như sau:
def destroy
if params[:product_ids].present?
Product.where(id: params[:product_ids]).destroy_all
end
respond_to do |format|
format.json{head :no_content}
end
end
Sửa lại views/products/index.slim như sau
#destroy-selected-products.fa.fa-trash-o
#products
table.table.table-striped.table-hover.table-bordered
thead
tr
th.text-center= t(".action")
th= t(".product_name")
th= t(".product_kind")
th= t(".jan_code")
tbody
- @products.each do |product|
tr.product
td.text-center= check_box_tag :product_ids, product.id, false,
class: "check-box-field"
td= product.name
td= product.product_kind
td= product.jan_code
Như vậy khi mình lựa chọn các products rồi bấm vào biểu tượng trash (thùng rác) thì sẽ xóa các records đó.
Thêm code vào products.coffee như sau:
$ ->
$("#destroy-selected-products").on "click", ->
product_ids = getSelectedCheckbox($("#products"))
confirm_msg = "Are you sure?"
if (product_ids.length > 0) && confirm(confirm_msg)
$.ajax
type: "DELETE"
dataType: "JSON"
url: "/products/bulk_product"
data: {product_ids: product_ids}
success: ->
$("#products").find(".check-box-field:checked").
parents(".product").remove()
return
getSelectedCheckbox = ($elem) ->
$elem.find(".check-box-field:checked").map((_, elem) ->
$(elem).val()
).get()
Như vậy mình đã thực hiện việc xóa nhiều records lựa chọn bằng 2 cách. 
All rights reserved