NOT NIL kullanarak durumun raylar


359

Raylar 3 stilini kullanarak tam tersini nasıl yazarım:

Foo.includes(:bar).where(:bars=>{:id=>nil})

Nerede id nil değil bulmak istiyorum. Denedim:

Foo.includes(:bar).where(:bars=>{:id=>!nil}).to_sql

Ama bu geri dönüyor:

=> "SELECT     \"foos\".* FROM       \"foos\"  WHERE  (\"bars\".\"id\" = 1)"

Kesinlikle ihtiyacım olan şey bu değil ve neredeyse ARel'de bir böcek gibi görünüyor.


2
!niliçin değerlendirir trueRuby ve AREL çevirir trueiçin 1bir SQL sorgusunda. Oluşturulan sorgu aslında istediğin şey - bu bir ARel hatası değildi.
yuval

Yanıtlar:


510

Rails 3 ile bunu yapmanın kanonik yolu:

Foo.includes(:bar).where("bars.id IS NOT NULL")

ActiveRecord 4.0 ve üstü ekler, where.notböylece bunu yapabilirsiniz:

Foo.includes(:bar).where.not('bars.id' => nil)
Foo.includes(:bar).where.not(bars: { id: nil })

Tablolar arasındaki kapsamlarla çalışırken, mergemevcut kapsamları daha kolay kullanabilmem için yararlanmayı tercih ederim .

Foo.includes(:bar).merge(Bar.where.not(id: nil))

Ayrıca, includesher zaman bir birleştirme stratejisi seçmediğinden, referencesburada da kullanmalısınız , aksi takdirde geçersiz SQL ile sonuçlanabilir.

Foo.includes(:bar)
   .references(:bar)
   .merge(Bar.where.not(id: nil))

1
Buradaki sonuncusu benim için çalışmıyor, bunun için fazladan bir mücevher veya eklentiye ihtiyacımız var mı? Anladım: rails undefined method 'not_eq' for :confirmed_at:Symbol..
Tim Baas

3
@ Zaman Evet, yukarıda bağladığım MetaWhere gem.
Adam Lassek

3
Biraz çirkin olsa bile diğer mücevherler gerektirmeyen çözümü
sevdim

1
@oreoshake MetaWhere / Squeel sahip olmaya değer, bu sadece küçük bir model. Ancak elbette genel bir vakayı bilmek iyidir.
Adam Lassek

1
@BKSpurgeon Zincirleme wherekoşulları basitçe bir AST oluşturuyor, eachveya gibi bir terminal yöntemine ulaşana kadar veritabanına çarpmıyor to_a. Sorguyu oluşturmak bir performans sorunu değildir; veritabanından talep ettiğiniz şey.
Adam Lassek

251

ARel'deki bir hata değil, mantığınızdaki bir hata.

Burada istediğiniz şey:

Foo.includes(:bar).where(Bar.arel_table[:id].not_eq(nil))

2
Nil'i

12
Bir tahminde,! Nil truebir boolean olan geri döner . SQLese :id => truealır id = 1.
zetetic

Bu, ham sql parçaları yazmaktan kaçınmanın iyi bir yoludur. Sözdizimi Squeel kadar özlü değil.
Kelvin

1
Bunu sqlite3 ile yapmayı başaramadım. sqlite3 görmek istiyor field_name != 'NULL'.
mjnissim

@zetetic Postgres kullanmadığınız sürece, bu durumda id = 't':)
thekingoftruth

36

Raylar için4:

Yani, istediğiniz bir iç birleşimdir, bu yüzden sadece birleşimleri yüklemelisiniz:

  Foo.joins(:bar)

  Select * from Foo Inner Join Bars ...

Ancak, kayıt için, bir "NOT NULL" koşulu istiyorsanız, sadece yüklem olmayan ifadeyi kullanın:

Foo.includes(:bar).where.not(bars: {id: nil})

Select * from Foo Left Outer Join Bars on .. WHERE bars.id IS NOT NULL

Bu sözdiziminin bir kullanımdan kaldırma bildirdiğini unutmayın (bir dize SQL snippet'i hakkında konuşur, ancak karma koşul ayrıştırıcıdaki dizeye değiştirildi mi sanırım?), Bu yüzden sonuna referans eklediğinizden emin olun:

Foo.includes(:bar).where.not(bars: {id: nil}).references(:bar)

DEPRECATION UYARI: Bir dizgi SQL snippet'inde başvurulan tablo (lar) ı (aşağıdakilerden biri: ....) yüklemeye hevesli görünüyorsunuz. Örneğin:

Post.includes(:comments).where("comments.title = 'foo'")

Şu anda, Active Record dizedeki tabloyu tanır ve yorumları ayrı bir sorguya yüklemek yerine yorum tablosuna sorguya KATILMAYI bilir. Ancak, bunu tam gelişmiş bir SQL ayrıştırıcısı yazmadan yapmak doğal olarak kusurludur. Bir SQL ayrıştırıcısı yazmak istemediğimizden, bu işlevi kaldırıyoruz. Şu andan itibaren, bir dizeden bir tabloya başvururken Active Record'a açıkça söylemelisiniz:

Post.includes(:comments).where("comments.title = 'foo'").references(:comments)

1
referencesÇağrı bana yardımcı oldu!
theblang


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.