Rails where condition using NOT NULL

Używając stylu rails 3 jak miałbym napisać przeciwieństwo:

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

Chcę znaleźć, gdzie id nie jest null. Próbowałem:

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

Ale to zwraca:

=> "SELECT     \"foos\".* FROM       \"foos\"  WHERE  (\"bars\".\"id\" = 1)"
To zdecydowanie nie jest to, czego potrzebuję, i wydaje się prawie jak robal w ARel.
Author: Jonathan Allard, 2010-11-23

5 answers

Kanoniczny sposób na zrobienie tego z Rails 3:

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

ActiveRecord 4.0 i wyżej dodaje where.not więc możesz to zrobić:

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

Podczas pracy z zakresami między tabelami, wolę wykorzystać merge żebym mógł łatwiej korzystać z istniejących zakresów.

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

Również, ponieważ includes nie zawsze wybiera strategię join, należy użyć references tutaj również, w przeciwnym razie możesz skończyć z nieprawidłowym SQL.

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

Już nie zaleca się użycie Squeel do tego celu, ponieważ nie zawsze ma on opiekuna na pełny etat i zależy to od prywatnych API, które powodują częste łamanie zmian.

 466
Author: Adam Lassek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-11 02:44:50

To nie błąd w Arelu, to błąd w Twojej logice.

To czego tu chcesz to:

Foo.includes(:bar).where(Bar.arel_table[:id].not_eq(nil))
 249
Author: Ryan Bigg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-23 03:53:14

Dla Kolejek4:

Więc to, czego chcesz, to wewnętrzne połączenie, więc naprawdę powinieneś użyć predykatu joins: {]}

  Foo.joins(:bar)

  Select * from Foo Inner Join Bars ...

Ale, dla przypomnienia, jeśli chcesz warunek "NOT NULL" po prostu użyj predykatu not:

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

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

Zauważ, że ta składnia zgłasza deprecjację (mówi o fragmencie string SQL, ale domyślam się, że warunek hash został zmieniony na string w parserze?), więc pamiętaj, aby dodać odwołania do końca:

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

Ostrzeżenie: wygląda jak jesteś chętny Ładowanie tabeli (s) (jeden z dnia: ....), do których odwołuje się ciąg znaków SQL. Na przykład:

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

Obecnie Active Record rozpoznaje tabelę w łańcuchu i zna aby dołączyć tabelę komentarzy do zapytania, zamiast wczytywać komentarze w osobnym zapytaniu. Jednak robiąc to bez pisania pełnowymiarowego Parser SQL jest z natury wadliwy. Ponieważ nie chcemy pisać SQL parser, usuwamy tę funkcjonalność. Od teraz musisz jawnie informuj rekord aktywny, gdy odwołujesz się do tabeli z string:

Post.includes(:comments).where("comments.title = 'foo'").references(:comments)
 36
Author: Matt Rogish,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-06 18:36:25

Z Rails 4 to proste:

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

Zobacz: http://guides.rubyonrails.org/active_record_querying.html#not-conditions

 22
Author: Tilo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-08 06:12:36

Nie jestem pewien, czy to jest pomocne, ale to, co działało dla mnie w Rails 4

Foo.where.not(bar: nil)
 16
Author: Raed Tulefat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-11 12:03:01