xóa_all vs hủy_all?


192

Tôi đang tìm cách tiếp cận tốt nhất để xóa các bản ghi từ một bảng. Chẳng hạn, tôi có một người dùng có ID người dùng ở nhiều bảng. Tôi muốn xóa người dùng này và mọi bản ghi có ID của anh ấy trong tất cả các bảng.

u = User.find_by_name('JohnBoy')
u.usage_indexes.destroy_all
u.sources.destroy_all
u.user_stats.destroy_all
u.delete

Điều này hoạt động và loại bỏ tất cả các tham chiếu của người dùng khỏi tất cả các bảng, nhưng tôi nghe nói rằng nó destroy_allrất nặng quá trình, vì vậy tôi đã thử delete_all. Nó chỉ xóa người dùng khỏi bảng người dùng của chính anh ta và idtừ tất cả các bảng khác được tạo thành null, nhưng để lại các bản ghi nguyên vẹn trong đó. Ai đó có thể chia sẻ quy trình chính xác để thực hiện một nhiệm vụ như thế này không?

Tôi thấy rằng destroy_allgọi destroyhàm trên tất cả các đối tượng liên quan nhưng tôi chỉ muốn xác nhận cách tiếp cận chính xác.

Câu trả lời:


242

Bạn đúng rồi. Nếu bạn muốn xóa Người dùng và tất cả các đối tượng được liên kết -> destroy_all Tuy nhiên, nếu bạn chỉ muốn xóa Người dùng mà không chặn tất cả các đối tượng được liên kết ->delete_all

Theo bài đăng này: Rails: phụ thuộc =>: hủy VS: phụ thuộc =>: xóa_all

  • destroy/ destroy_all: Các đối tượng liên quan bị hủy cùng với đối tượng này bằng cách gọi phương thức hủy của chúng
  • delete/ delete_all: Tất cả các đối tượng liên quan bị hủy ngay lập tức mà không gọi phương thức: hủy của chúng

80
Cũng cần lưu ý rằng 1) Cuộc gọi lại không được gọi khi sử dụng delete_allvà 2) destroy_allkhởi tạo tất cả các bản ghi và hủy chúng cùng một lúc, vì vậy với một tập dữ liệu rất lớn, điều này có thể rất chậm.
Dylan Markow

giả sử tôi đang chạy một phương thức before_destroy trong mô hình - nếu tôi sử dụng xóa_all thì phương thức này sẽ không chạy? Thứ hai, nếu tôi sử dụng một phương thức before_delete trong mô hình của mình, nó sẽ chạy khi tôi chạy xóa hoặc xóa_all trong bảng điều khiển rails?
BKSpurgeon

23

xóa_all là một câu lệnh XÓA SQL duy nhất và không có gì nữa. hủy_all gọi hàm kill () trên tất cả các kết quả khớp của: điều kiện (nếu bạn có) có thể ít nhất là NUM_OF_RESULTS câu lệnh SQL.

Nếu bạn phải làm một cái gì đó quyết liệt như kill_all () trên tập dữ liệu lớn, tôi có thể sẽ không làm điều đó từ ứng dụng và xử lý nó một cách cẩn thận. Nếu tập dữ liệu đủ nhỏ, bạn sẽ không bị tổn thương nhiều.


16

Để tránh thực tế là destroy_allkhởi tạo tất cả các bản ghi và hủy chúng cùng một lúc, bạn có thể sử dụng nó trực tiếp từ lớp mô hình.

Vì vậy, thay vì:

u = User.find_by_name('JohnBoy')
u.usage_indexes.destroy_all

Bạn có thể làm :

u = User.find_by_name('JohnBoy')
UsageIndex.destroy_all "user_id = #{u.id}"

Kết quả là một truy vấn để hủy tất cả các bản ghi liên quan


1
Nó sẽ gọi các cuộc gọi lại hủy trên các bản ghi liên quan, hoặc UsageIndex.destroy_alltương đương với UsageIntex.delete_all?
Magne

UsageIndex.destroy_allkhông còn khả dụng kể từ đường ray 3
Fabriciofreitag

1

Tôi đã tạo ra một viên ngọc nhỏ có thể giảm bớt nhu cầu xóa thủ công các hồ sơ liên quan trong một số trường hợp.

Viên ngọc này thêm một tùy chọn mới cho các hiệp hội ActiveRecord:

phụ thuộc :: xóa_recursively

Khi bạn hủy bản ghi, tất cả các bản ghi được liên kết bằng tùy chọn này sẽ bị xóa theo cách đệ quy (tức là trên các mô hình), mà không khởi tạo bất kỳ bản ghi nào.

Lưu ý rằng, giống như phụ thuộc :: xóa hoặc phụ thuộc :: xóa_all, tùy chọn mới này không kích hoạt các cuộc gọi lại xung quanh / trước / after_destroy của các bản ghi phụ thuộc.

Tuy nhiên, có thể có sự phụ thuộc :: phá hủy các hiệp hội ở bất cứ đâu trong một chuỗi các mô hình có liên quan đến phụ thuộc :: xóa_recursively. Tùy chọn hủy: sẽ hoạt động bình thường ở bất cứ đâu lên hoặc xuống dòng, khởi tạo và hủy tất cả các bản ghi có liên quan và do đó cũng kích hoạt các cuộc gọi lại của chúng.


Cái này thật tuyệt! Tôi tự hỏi tại sao không có nhiều người đã xem / đánh dấu sao / rẽ nhánh nó trên github .. nó vẫn hoạt động tốt chứ?
Magne

@Magne Cảm ơn! Nó nên được làm việc. Các thử nghiệm chạy trên Ruby 2.4.1 và Rails 5.1.1. Cho đến nay tôi chỉ sử dụng nó một cách riêng tư và không sử dụng trong các ứng dụng sản xuất chính, do đó phiên bản chính "0", nhưng tôi không bao giờ nhận thấy bất kỳ vấn đề nào. Nó cũng khá đơn giản, vì vậy nó sẽ ổn thôi.
Janosch

Mát mẻ. :) Tôi đang chạy một dự án trên Ruby 2.3.1 và 'rails', '~> 4.1.14', và thật đáng buồn khi buộc phải dựa vào Activerecord (~> 4.1.0) do các loại đá quý khác. Tôi thấy rằng xóa_recursively được giải quyết thành 0.9.0. Có phiên bản cũ hơn của nó sẽ hoạt động với Activerecord 4.1 không? Tôi không thể tìm thấy bất kỳ trong tab phát hành trên github.
Magne

1
@Magne Tôi thấy nó thực sự hoạt động cho Activerecord ở mức thấp 4.1,14 và đã phát hành phiên bản đá quý 1.0.0 với sự phụ thuộc thoải mái. Tuy nhiên, hãy nhớ rằng chi nhánh 4.1 của Rails không còn nhận được cập nhật bảo mật nữa.
Janosch
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.