delete_all vs destroy_all?


193

ฉันกำลังมองหาวิธีที่ดีที่สุดในการลบบันทึกออกจากตาราง ตัวอย่างเช่นฉันมีผู้ใช้ที่มี ID ผู้ใช้อยู่ในหลาย ๆ ตาราง ฉันต้องการลบผู้ใช้นี้และทุกระเบียนที่มี ID ของเขาในตารางทั้งหมด

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

งานนี้และลบข้อมูลทั้งหมดของผู้ใช้จากตารางทั้งหมด แต่ผมได้ยินมาว่าเป็นอย่างมากกระบวนการหนักดังนั้นฉันพยายามdestroy_all delete_allมันจะลบผู้ใช้ออกจากตารางผู้ใช้ของเขาเองและidจากตารางอื่น ๆ ทั้งหมดจะถูกทำให้เป็นโมฆะ แต่จะทำให้ระเบียนนั้นไม่เปลี่ยนแปลง ใครสามารถแบ่งปันสิ่งที่กระบวนการที่ถูกต้องสำหรับการทำงานเช่นนี้?

ฉันเห็นว่าdestroy_allเรียกใช้destroyฟังก์ชันบนวัตถุที่เกี่ยวข้องทั้งหมด แต่ฉันต้องการยืนยันวิธีการที่ถูกต้อง

คำตอบ:


244

คุณพูดถูก ถ้าคุณต้องการที่จะลบผู้ใช้และวัตถุที่เกี่ยวข้องทั้งหมด -> destroy_all อย่างไรก็ตามถ้าคุณเพียงแค่ต้องการที่จะลบผู้ใช้โดยไม่ต้องระงับวัตถุที่เกี่ยวข้องทั้งหมด ->delete_all

ตามโพสต์นี้: Rails: dependent =>: destroy VS: dependent =>: delete_all

  • destroy/ destroy_all: วัตถุที่เกี่ยวข้องถูกทำลายพร้อมกับวัตถุนี้โดยเรียกวิธีการทำลาย
  • delete/ delete_all: วัตถุที่เกี่ยวข้องทั้งหมดถูกทำลายทันทีโดยไม่ต้องเรียกใช้: ทำลายวิธี

80
ควรสังเกตว่า 1) การโทรกลับไม่ได้ถูกเรียกเมื่อใช้delete_allและ 2) destroy_allสร้างระเบียนทั้งหมดและทำลายระเบียนทีละรายการดังนั้นชุดข้อมูลที่มีขนาดใหญ่มากอาจทำให้ช้าลงอย่างเจ็บปวด
Dylan Markow

สมมติว่าฉันใช้วิธี before_destroy ในรูปแบบ - ถ้าฉันใช้ delete_all แล้ววิธีนี้จะไม่ทำงาน ประการที่สองถ้าฉันใช้เมธอด before_delete ในโมเดลของฉันการรันนี้จะรันเมื่อฉันลบหรือ delete_all ในคอนโซลทางรถไฟหรือไม่?
BKSpurgeon

23

delete_all เป็นคำสั่ง SQL DELETE คำเดียวและไม่มีอะไรเพิ่มเติม destroy_all เรียกใช้ destroy () สำหรับผลลัพธ์ที่ตรงกันทั้งหมดของ: เงื่อนไข (ถ้าคุณมี) ซึ่งอาจมีอย่างน้อย NUM_OF_RESULTS คำสั่ง SQL

หากคุณต้องทำอะไรที่รุนแรงเช่น destroy_all () บนชุดข้อมูลขนาดใหญ่ฉันอาจจะไม่ทำมันจากแอพและจัดการด้วยตนเองด้วยความระมัดระวัง หากชุดข้อมูลมีขนาดเล็กพอคุณจะไม่เจ็บมาก


16

เพื่อหลีกเลี่ยงความจริงที่ทำให้destroy_allอินสแตนซ์เร็กคอร์ดทั้งหมดและทำลายทีละรายการคุณสามารถใช้มันโดยตรงจากคลาสโมเดล

ดังนั้นแทนที่จะ:

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

คุณทำได้ :

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

ผลลัพธ์เป็นหนึ่งแบบสอบถามเพื่อทำลายระเบียนที่เกี่ยวข้องทั้งหมด


1
มันจะเรียก callbacks ทำลายในบันทึกที่เกี่ยวข้องหรือUsageIndex.destroy_allเทียบเท่ากับUsageIntex.delete_all?
Magne

UsageIndex.destroy_allไม่สามารถใช้ได้อีกนับตั้งแต่ราง 3
fabriciofreitag

1

ฉันได้สร้างอัญมณีขนาดเล็กที่สามารถลดความจำเป็นในการลบระเบียนที่เกี่ยวข้องด้วยตนเองในบางสถานการณ์

อัญมณีนี้เพิ่มตัวเลือกใหม่สำหรับการเชื่อมโยง ActiveRecord:

ขึ้นอยู่กับ:: delete_recursively

เมื่อคุณทำลายระเบียนระเบียนทั้งหมดที่เกี่ยวข้องกับการใช้ตัวเลือกนี้จะถูกลบซ้ำ (เช่นข้ามรุ่น) โดยไม่ต้องสร้างระเบียนใด ๆ เลย

โปรดทราบว่าเช่นเดียวกับ dependent:: delete or dependent:: delete_all ตัวเลือกใหม่นี้จะไม่เรียกการเรียกกลับรอบ / ก่อน / after_destroy ของเร็กคอร์ดที่ขึ้นต่อกัน

อย่างไรก็ตามมีความเป็นไปได้ที่จะพึ่งพา:: ทำลายการเชื่อมโยงที่ใดก็ได้ภายในห่วงโซ่ของแบบจำลองที่เกี่ยวข้องเป็นอย่างอื่น:: delete_recursively ตัวเลือกทำลาย: จะทำงานตามปกติทุกที่บนหรือล่างบรรทัดยกตัวอย่างและทำลายระเบียนที่เกี่ยวข้องทั้งหมดและทำให้เกิดการเรียกกลับ


มันยอดเยี่ยมมาก! ฉันสงสัยว่าทำไมไม่มีคนดู / ติดดาว / แยกมันบน GitHub อีกต่อไป .. มันยังทำงานได้ดีอยู่ใช่ไหม?
Magne

@Magne ขอบคุณ! มันควรจะทำงาน การทดสอบรันบน Ruby 2.4.1 และ Rails 5.1.1 จนถึงตอนนี้ฉันใช้มันเป็นการส่วนตัวและไม่ได้อยู่ในแอพพลิเคชั่นหลัก ๆ ดังนั้นรุ่นใหญ่ "0" แต่ฉันไม่เคยสังเกตเห็นปัญหาใด ๆ มันค่อนข้างง่ายดังนั้นควรปรับ
Janosch

เย็น. :) ฉันกำลังใช้งานโครงการ Ruby 2.3.1 และ 'rails', '~> 4.1.14' และฉันถูกบังคับให้ต้องพึ่งพา activerecord (~> 4.1.0) เนื่องจากอัญมณีอื่น ๆ ฉันเห็นว่า delete_recursively ได้รับการแก้ไขเป็น 0.9.0 มีเวอร์ชั่นเก่ากว่าที่สามารถใช้กับ activerecord 4.1 ได้หรือไม่? ฉันไม่พบรายการใด ๆ ในแท็บเผยแพร่บน GitHub
Magne

1
@Magne ฉันพบว่ามันใช้งานได้จริงสำหรับ activerecord ที่ต่ำเพียง 4.1.14และได้เปิดตัว gem เวอร์ชั่น 1.0.0 ที่มีการพึ่งพาที่ผ่อนคลาย โปรดจำไว้ว่า Rails '4.1 branch ไม่ได้รับการอัพเดทด้านความปลอดภัยอีกต่อไป
Janosch
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.