วิธีการเลือกตำแหน่ง ID ใน Array Rails ActiveRecord โดยไม่มีข้อยกเว้น


138

เมื่อฉันมีอาร์เรย์ของรหัสเช่น

ids = [2,3,5]

และฉันแสดง

Comment.find(ids)

ทุกอย่างทำงานได้ดี แต่เมื่อมี id ที่ไม่มีอยู่ฉันจะได้รับข้อยกเว้น สิ่งนี้เกิดขึ้นโดยทั่วไปเมื่อฉันได้รับรายการ ID ที่ตรงกับตัวกรองบางตัวและมากกว่าที่ฉันทำ

current_user.comments.find(ids)

คราวนี้ฉันอาจมีรหัสความคิดเห็นที่ถูกต้องซึ่งไม่ได้เป็นของผู้ใช้ที่ระบุดังนั้นจึงไม่พบและฉันได้รับข้อยกเว้น

ฉันได้ลองfind(:all, ids)แล้ว แต่มันส่งคืนระเบียนทั้งหมด

วิธีเดียวที่ฉันทำได้ตอนนี้คือ

current_user.comments.select { |c| ids.include?(c.id) }

แต่สำหรับฉันดูเหมือนวิธีแก้ปัญหาที่ไม่มีประสิทธิภาพมาก

มีวิธีที่ดีกว่าในการเลือกID ใน Arrayโดยไม่ได้รับข้อยกเว้นในเรกคอร์ดที่ไม่มีอยู่หรือไม่?

คำตอบ:


221

หากเป็นเพียงการหลีกเลี่ยงข้อยกเว้นที่คุณกังวลฟังก์ชันตระกูล "find_all_by .. " จะทำงานโดยไม่มีข้อยกเว้น

Comment.find_all_by_id([2, 3, 5])

จะใช้งานได้แม้ว่าจะไม่มีรหัสบางตัวก็ตาม ใช้งานได้ในไฟล์

user.comments.find_all_by_id(potentially_nonexistent_ids)

กรณีเช่นกัน.

อัปเดต: Rails 4

Comment.where(id: [2, 3, 5])

นี่เป็นทางออกที่ฉันชอบดูเหมือนว่าจะสะอาดกว่าเส้นทางการจัดการข้อยกเว้น
Sam Saffron

5
ในฐานะที่เป็นส่วนขยายอื่นสำหรับสิ่งนี้คุณจำเป็นต้องเชื่อมโยงเงื่อนไขที่ซับซ้อนคุณสามารถทำได้ Comment.all (: เงื่อนไข => ["ได้รับการอนุมัติและ id ใน (?)", [1,2,3]])
Omar Qureshi

14
สิ่งนี้จะเลิกใช้ใน Rails 4: edgeguides.rubyonrails.org/…
Jonathan Lin

3
@JonathanLin ถูกต้องควรเลือกคำตอบของ mjnissim: stackoverflow.com/a/11457025/33226
Gavin Miller

7
สิ่งนี้จะส่งกลับค่าArrayแทนActiveRecord::Relationซึ่งจะ จำกัด สิ่งที่คุณสามารถทำได้ในภายหลัง Comment.where(id: [2, 3, 5])ส่งคืนActiveRecord::Relationไฟล์.
Joshua Pinter

149

อัปเดต: คำตอบนี้เกี่ยวข้องกับ Rails 4.x มากขึ้น

ทำเช่นนี้:

current_user.comments.where(:id=>[123,"456","Michael Jackson"])

ด้านที่ดีกว่าของแนวทางนี้คือการส่งคืนRelationวัตถุซึ่งคุณสามารถเข้าร่วม.whereอนุ.limitประโยคอนุประโยค ฯลฯ ได้มากขึ้นซึ่งมีประโยชน์มาก นอกจากนี้ยังอนุญาตให้ใช้ ID ที่ไม่มีอยู่จริงโดยไม่มีข้อยกเว้น

ไวยากรณ์ Ruby ที่ใหม่กว่าจะเป็น:

current_user.comments.where(id: [123, "456", "Michael Jackson"])

ขอขอบคุณที่ยืนยันwhereไวยากรณ์เมื่อเปรียบเทียบกับอาร์เรย์ ฉันคิดว่าฉันอาจจะต้อง SQL รหัสที่มีINคำสั่ง scoped_by_idแต่ทำความสะอาดลักษณะและจะเปลี่ยนง่ายสำหรับผู้ที่เลิก
Mark Berry

1
สิ่งนี้เรียกว่าอะไรและทำงานอย่างไร? มันเป็นเวทย์มนตร์ Rails หรือไม่! ตามที่เพื่อนร่วมงานแสดงความคิดเห็นคล้ายกับ "การเปรียบเทียบจำนวนเต็มกับรายการวัตถุ"
atw

23

หากคุณต้องการการควบคุมมากขึ้น (บางทีคุณอาจต้องระบุชื่อตาราง) คุณสามารถทำสิ่งต่อไปนี้ได้:

Model.joins(:another_model_table_name)
  .where('another_model_table_name.id IN (?)', your_id_array)

สิ่งที่ฉันกำลังมองหา ขอบคุณ!
Myxtic

มีวิธีใดบ้างที่จะรักษาลำดับyour_id_arrayเวลาที่คุณได้รับวัตถุคืน?
Joshua Pinter

@JoshPinter ฉันไม่คิดว่านี่เป็นวิธีที่เชื่อถือได้ในการคาดหวังว่าฐานข้อมูลจะส่งคืนสิ่งต่างๆในลำดับเดียวกัน บางทีอาจเพิ่มคำค้นหา ORDER BY ในตอนท้ายเพื่อให้แน่ใจว่าลำดับสิ่งต่างๆถูกต้อง
Jonathan Lin

@JonathanLin ขอบคุณสำหรับการตอบสนองของโจนาธาน คุณพูดถูกอย่างแน่นอน การใช้คำสั่งORDER BYจะไม่ทำงานในสถานการณ์ของฉันเนื่องจากคำสั่งไม่ได้ขึ้นอยู่กับแอตทริบิวต์ อย่างไรก็ตามมีวิธีดำเนินการผ่าน SQL (เร็วมาก) และมีคนสร้างอัญมณีขึ้นมาด้วย ดูคำถาม & คำตอบนี้: stackoverflow.com/questions/801824/…
Joshua Pinter

10

ตอนนี้เมธอด. find และ. find_by_id เลิกใช้แล้วในราง 4 ดังนั้นเราสามารถใช้ด้านล่างแทน:

Comment.where(id: [2, 3, 5])

มันจะทำงานได้แม้ว่าจะไม่มีรหัสบางตัวก็ตาม ใช้งานได้ในไฟล์

user.comments.where(id: avoided_ids_array)

นอกจากนี้สำหรับการยกเว้น ID

Comment.where.not(id: [2, 3, 5])

4
github.com/rails/activerecord-deprecated_finders .find และ. find_by_id วิธีการไม่เลิกใช้ในราง 4
Canna

0

เพื่อหลีกเลี่ยงข้อยกเว้นในการฆ่าแอปของคุณคุณควรจับข้อยกเว้นเหล่านั้นและปฏิบัติตามที่คุณต้องการโดยกำหนดพฤติกรรมสำหรับแอปของคุณในสถานการณ์ที่ไม่พบรหัส

begin
  current_user.comments.find(ids)
rescue
  #do something in case of exception found
end

นี่คือข้อมูลเพิ่มเติมเกี่ยวกับข้อยกเว้นในทับทิม


1
ใช่วิธีนี้ช่วยแก้ปัญหาได้ แต่มันไม่ใช่วิธีแก้ปัญหาที่สะอาดจริงๆ
Jakub Arnold

3
หากคุณกำลังจะพบข้อยกเว้นคุณควรประกาศข้อยกเว้นที่คุณคาดว่าจะจับได้มิฉะนั้นคุณจะเสี่ยงที่จะจับสิ่งที่คุณไม่คาดคิดและซ่อนปัญหาที่แท้จริงไว้
Haegin

0

คุณยังสามารถใช้ใน named_scope ได้หากต้องการใส่เงื่อนไขอื่น ๆ

ตัวอย่างเช่นรวมรุ่นอื่น ๆ :

named_scope 'get_by_ids', แลมด้า {| ids | {: include => [: comments],: condition => ["comments.id IN (?)", ids]}}

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.