Rails 5: ActiveRecord หรือแบบสอบถาม


109

คุณทำorแบบสอบถามในRails 5 ActiveRecord ได้อย่างไร? นอกจากนี้ยังสามารถเชื่อมโยงorกับwhereในแบบสอบถาม ActiveRecord ได้หรือไม่


คำตอบ:


228

ความสามารถในการห่วงโซ่orข้อพร้อมกับwhereประโยคหนึ่งในActiveRecordแบบสอบถามจะสามารถใช้ได้ในRails 5 ดูการอภิปรายที่เกี่ยวข้องและคำขอดึงการอภิปรายที่เกี่ยวข้องและขอดึง

ดังนั้นคุณจะสามารถทำสิ่งต่อไปนี้ในRails 5 :

ที่จะได้รับpostมีid1 หรือ 2:

Post.where('id = 1').or(Post.where('id = 2'))

ตัวอย่างอื่น ๆ :

(A && B) || ค:

    Post.where(a).where(b).or(Post.where(c))

(A || B) && C:

    Post.where(a).or(Post.where(b)).where(c)

3
ฉันจะได้รับ (A || B) && (C || D) ได้อย่างไร ฉันลอง Post.where (a) หรือ (Post.where (b)) โดยที่ (c) หรือ (Post.where (d)) แต่มันสร้างเป็น: (A || B) && C || D
Imran Ahmad

3
@Imran ฉันเชื่อว่ามันPost.where(a).or(Post.where(b)).where(Post.where(c).or(Post.where(d)))ควรจะสร้าง (a || b) && (c || d)
engineermnky

1
@ อิมรานนี่ดูเหมือนจะไม่ได้ผลสำหรับฉัน: ฉันได้รับArgumentError: Unsupported argument type: #<MyModel::ActiveRecord_Relation:0x00007f8edbc075a8> (MyModel::ActiveRecord_Relation)
สวน

5
เทียบเท่ากับ. or ที่รับความสัมพันธ์และสร้างและเป็น. merge (A || B) && (C || D) ผลิตได้โดย Post.where (a). หรือ (Post.where (b)). merge (Post.where (c) .or (Post.where (d )))
Siim Liiser

2
@MathieuJ. เป็น ActiveRecord :: Relation # merge api.rubyonrails.org/classes/ActiveRecord/…
Siim Liiser

13

เราไม่จำเป็นต้องรอให้ราง 5 ใช้ORแบบสอบถามนี้ เรายังสามารถใช้กับrails 4.2.3ไฟล์. มีย้ายกลับเป็นที่นี่

ขอบคุณEric-Guoสำหรับอัญมณีที่หรือตอนนี้เราสามารถเพิ่มORฟังก์ชัน>= rails 4.2.3นี้โดยใช้อัญมณีนี้ได้


6

(เพิ่มเติมจากคำตอบของ KM Rakibul Islam)

การใช้ขอบเขตรหัสจะสวยขึ้น (ขึ้นอยู่กับดวงตาที่มอง):

scope a,      -> { where(a) }
scope b,      -> { where(b) }

scope a_or_b, -> { a.or(b) }

5

ฉันต้องทำ (A && B) || (C && D) || (E && F)

แต่ใน Rails 5.1.4สถานะปัจจุบันของสิ่งนี้ซับซ้อนเกินกว่าที่จะทำได้ด้วย Arel หรือ-chain แต่ฉันยังคงต้องการใช้ Rails เพื่อสร้างแบบสอบถามให้มากที่สุด

ดังนั้นฉันจึงทำการแฮ็กเล็ก ๆ :

ในโมเดลของฉันฉันสร้างเมธอดส่วนตัวที่เรียกว่าsql_where:

private
  def self.sql_where(*args)
    sql = self.unscoped.where(*args).to_sql
    match = sql.match(/WHERE\s(.*)$/)
    "(#{match[1]})"
  end

ถัดไปในขอบเขตของฉันฉันสร้างอาร์เรย์เพื่อเก็บ OR

scope :whatever, -> {
  ors = []

  ors << sql_where(A, B)
  ors << sql_where(C, D)
  ors << sql_where(E, F)

  # Now just combine the stumps:
  where(ors.join(' OR '))
}

ซึ่งจะให้ผลลัพธ์การค้นหาที่คาดหวัง: SELECT * FROM `models` WHERE ((A AND B) OR (C AND D) OR (E AND F)).

และตอนนี้ฉันสามารถรวมสิ่งนี้กับขอบเขตอื่น ๆ ได้อย่างง่ายดายโดยไม่ผิดพลาดหรือของ

ความสวยความงามเป็นที่ sql_where ของฉันใช้เวลาปกติที่ข้อโต้แย้งข้อ: จะสร้างsql_where(name: 'John', role: 'admin')(name = 'John' AND role = 'admin')


ฉันคิดว่าคุณสามารถใช้.mergeเทียบเท่ากับ && และสร้างต้นไม้ที่เหมาะสมเพื่อจับภาพ parens ของคุณ บางอย่าง ... (scopeA.merge(scopeB)).or(scopeC.merge(scopeD)).or(scopeE.merge(scopeF))สมมติว่าแต่ละขอบเขตมีลักษณะเป็นModel.where(...)
nar8789

ตรวจสอบสิ่งนี้ก่อนใช้ merge - github.com/rails/rails/issues/33501
Aarthi

1

ราง 5 มีความสามารถสำหรับประโยคที่มีor whereตัวอย่างเช่น.

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