5

Ben test amaçlı olarak bir modelNegate ActiveRecord sorgu kapsamı

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 

üzerinde biraz karmaşık kapsamını var, emin olmak için hepsi Contactsdeğilgroup_search doğru nedenlerle dışlanır tarafından döndürülen. o listeyi almak için Ama

, ben

iki sorgu çalıştırır
Contact.all - Contact.group_search('query') 

, yerine Relation bir Array döndürür ve İsterdim daha yavaştır yüklemek zorunda.

Ve group_search kapsamını test ettiğimden, no'lu başka bir kapsamı, negatif olan noktayı bozar. Bunu yapmanın bir yolu

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

var mı:

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

aşağıdaki SQL sorgusu oluşturmak için: Daha doğrusu bir şey gibi yapardım? Bu çözüm Raylar 4.x çalışmak için, diziler olarak kapsamındaki değerleri sağlamalıdır

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

:

+0

Biraz daha hızlı bir şekilde olabilir: 'Contact.where.not (id: Contact.group_search ('query'). Pluck (: id))'. Hala iki sorgu, ancak bir ilişki döndürecek ve sorgulardan birini büyük ölçüde sınırlayacaktır. AFAIK, kapsamı reddetmenin bir yolu yok. – BroiSatse

+0

Evet ... ayrıca sorgunun kendisi de çok büyük olabilir ... bu tablonun 100k kayıt sırasına bir şey var ve ID'leri UUID'ler, yani eğer "istemiyorum (çok yaygın)" Sadece sorgu dizesi için megabaytta. – PJSCopeland

cevap

7

Sana kapsamını negating denir aradıklarını, aşağıdakileri deneyebilirsiniz düşünüyorum :

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

I'v da düzgün bir general implementation for negating the scopes, ayrıca ilginç bulabilir bulundu.

+0

Teşekkürler! Ama neden dizileri kullanmalıyım? – PJSCopeland

+0

Bu mükemmel çalışmalı gibi görünüyor - ne yazık ki SQL Server bu konuda bir kaltak olmak gibi görünüyor: 'TinyTds :: Hata:') 'yakın bir durumda beklenen bir bağlamda belirtilen boolean olmayan bir ifadenin bir ifadesi. : EXEC sp_executesql N'SELECT [contact]. * FROM [contact] WHERE (NOT ([contact]. [Contact_type] = 2308 VE [contact]. [Inactive] = 0 VE N''last_name LIKE '' ''% sorgu % '' '' '')) '' – PJSCopeland

+0

@Patrick: Neden olduğunu bilmiyorum, ancak Raylar, değerler diziler halinde sağlanmamışsa, argümanlar bağlayıcı değildir, Rails 4.2'de görünen bilinen bir hata gibi görünüyor. Hangi sürümü kullanıyorsunuz? – potashin