5

Tôi có một phạm vi hơi phức tạp trên một mô hìnhphủ nhận ActiveRecord phạm vi truy vấn

class Contact < ActiveRecord::Base 
    scope :active,  -> { where(inactive: false) } 
    scope :groups,  -> { where(contact_type: 2308) } 
    scope :group_search, -> (query) do 
    active.groups.where("last_name LIKE '%' + ? + '%'", query) 
    end 
end 

Đối với mục đích thử nghiệm, tôi muốn chắc chắn rằng tất cả Contactskhông trả về bởi group_search bị loại trừ vì những lý do đúng đắn.

Nhưng để có được danh sách đó, tôi phải nạp

Contact.all - Contact.group_search('query') 

chạy hai truy vấn, trả về một Array thay vì một Relation, và là chậm hơn so với tôi muốn.

Và vì tôi đang thử nghiệm phạm vi group_search, hãy viết một phạm vi khác là tiêu cực của nó sẽ làm hỏng điểm. Tôi chỉ muốn làm một cái gì đó như:

Contact.merge.not(Contact.group_search('query')) 

để tạo ra các truy vấn SQL sau:

SELECT * 
FROM contacts 
WHERE NOT (contact_type = 2308 AND inactive = 0 AND last_name LIKE '%' + ? + '%') 

Có cách nào để làm điều này?

+0

Cách nhanh hơn một chút sẽ là: 'Contact.where.not (id: Contact.group_search ('query'). Pluck (: id))'. Vẫn còn hai truy vấn, nhưng sẽ trả về một mối quan hệ và sẽ hạn chế đáng kể một trong các truy vấn. AFAIK, không có cách nào để phủ nhận phạm vi atm. – BroiSatse

+0

Vâng ... bản thân truy vấn cũng có khả năng nhận được rất lớn ... bảng này có thứ gì đó với thứ tự 100 nghìn bản ghi và ID là UUID, vì vậy nếu tôi muốn "không (cái gì đó rất phổ biến)", tôi có thể tìm kiếm ở megabyte chỉ dành cho chuỗi truy vấn. – PJSCopeland

Trả lời

7

Tôi nghĩ rằng những gì bạn đang tìm kiếm được gọi là phủ nhận phạm vi, bạn có thể thử như sau:

conditions = Contact.group_search('query').where_values 
@contacts = Contact.where.not(conditions.reduce(:and)) 

Đối với giải pháp này để làm việc trong Rails 4.x, bạn nên cung cấp giá trị trong phạm vi như mảng :

scope :groups, -> { where(contact_type: [2308]) } 

I'v cũng tìm thấy gọn gàng general implementation for negating the scopes, bạn cũng có thể thấy thú vị.

+0

Cảm ơn! Nhưng tại sao tôi nên sử dụng mảng? – PJSCopeland

+0

Điều này có vẻ như nó sẽ hoạt động hoàn hảo - không may có vẻ như SQL Server là một bitch về điều này: 'TinyTds :: Lỗi: Một biểu thức của kiểu không boolean được chỉ định trong một ngữ cảnh mà điều kiện được mong đợi, gần ')'. : EXEC sp_executesql N'SELECT [liên hệ]. * TỪ [liên hệ] Ở ĐÂU (KHÔNG ([liên hệ]. [Contact_type] = 2308 VÀ [liên hệ]. [Không hoạt động] = 0 AND N''last_name LIKE '' ''% truy vấn % '' '' '')) '' – PJSCopeland

+0

@Patrick: Tôi không biết tại sao, nhưng Rails không phải là đối số ràng buộc nếu các giá trị không được cung cấp dưới dạng mảng, nó có vẻ là một lỗi đã biết xuất hiện trong Rails 4.2. Bạn sử dụng phiên bản nào? – potashin

Các vấn đề liên quan