Rails 5: ActiveRecord OR truy vấn


Câu trả lời:


228

Khả năng xâu chuỗi ormệnh đề cùng với wheremệnh đề trong ActiveRecordtruy vấn sẽ có sẵn trong Rails 5 . Xem thảo luận liên quan và yêu cầu kéo .

Vì vậy, bạn sẽ có thể thực hiện những việc sau trong Rails 5 :

Để có được một postvới id1 hoặc 2:

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

Một số ví dụ khác:

(A && B) || C:

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

(A || B) && C:

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

3
Làm thế nào tôi có thể nhận được (A || B) && (C || D). Tôi đã thử Post.where (a) .or (Post.where (b)). Where (c) .or (Post.where (d)) nhưng Nó tạo ra là: (A || B) && C || D
Imran Ahmad

3
@Imran Tôi tin rằng nó sẽ là Post.where(a).or(Post.where(b)).where(Post.where(c).or(Post.where(d)))cái này nên tạo (a || b) && (c || d)
kỹ

1
@Imran Điều này dường như không hiệu quả với tôi: Tôi hiểuArgumentError: Unsupported argument type: #<MyModel::ActiveRecord_Relation:0x00007f8edbc075a8> (MyModel::ActiveRecord_Relation)
Suan

5
Tương đương với .or nhận một quan hệ và tạo ra một và là .merge. (A || B) && (C || D) có thể được sản xuất bởi Post.where (a) .or (Post.where (b)). Merge (Post.where (c) .or (Post.where (d )))
Siim Liiser

2
@MathieuJ. Đó là hợp nhất ActiveRecord :: Relation #. api.rubyonrails.org/classes/ActiveRecord/…
Siim Liiser

13

Chúng ta không cần đợi rails 5 để sử dụng ORtruy vấn này . Chúng tôi cũng có thể sử dụng nó với rails 4.2.3. Có một cổng hậu ở đây .

Cảm ơn Eric-Guo vì gem where-or , Bây giờ chúng ta có thể thêm ORchức năng >= rails 4.2.3này bằng cách sử dụng gem này.


6

(Chỉ là một bổ sung cho câu trả lời của KM Rakibul Islam.)

Sử dụng phạm vi, mã có thể trở nên đẹp hơn (tùy thuộc vào mắt nhìn):

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

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

5

Tôi cần phải làm một (A && B) || (C && D) || (E && F)

Nhưng ở 5.1.4trạng thái hiện tại của Rails , điều này quá phức tạp để thực hiện với Arel hoặc chuỗi. Nhưng tôi vẫn muốn sử dụng Rails để tạo càng nhiều truy vấn càng tốt.

Vì vậy, tôi đã thực hiện một hack nhỏ:

Trong mô hình của mình, tôi đã tạo một phương thức riêng được gọi là sql_where:

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

Tiếp theo trong phạm vi của tôi, tôi đã tạo một mảng để giữ 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 '))
}

Mà sẽ tạo ra kết quả truy vấn mong đợi: SELECT * FROM `models` WHERE ((A AND B) OR (C AND D) OR (E AND F)).

Và bây giờ tôi có thể dễ dàng kết hợp điều này với các phạm vi khác, v.v. mà không có bất kỳ HOẶC sai trái nào.

Vẻ đẹp là sql_where của tôi nhận các đối số mệnh đề where-bình thường: sql_where(name: 'John', role: 'admin')sẽ tạo ra (name = 'John' AND role = 'admin').


Tôi nghĩ rằng bạn có thể sử dụng .mergetương đương với && và xây dựng một cái cây thích hợp để chụp các parens của bạn. Một cái gì đó giống như ... (scopeA.merge(scopeB)).or(scopeC.merge(scopeD)).or(scopeE.merge(scopeF)), giả sử mỗi người trong số các phạm vi ngoại hình giống nhưModel.where(...)
nar8789

Kiểm tra điều này trước khi sử dụng hợp nhất - github.com/rails/rails/issues/33501
Aarthi

1

Rails 5 có khả năng cho ormệnh đề với where. Ví dụ.

User.where(name: "abc").or(User.where(name: "abcd"))
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.