Рельсы, где условие с использованием NOT NIL - PullRequest
349 голосов
/ 23 ноября 2010

Используя стиль rails 3, я бы написал противоположное:

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

Я хочу найти, где идентификатор не ноль. Я попробовал:

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

Но это возвращает:

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

Это определенно не то, что мне нужно, и почти похоже на ошибку в ARel.

Ответы [ 5 ]

494 голосов
/ 23 ноября 2010

Канонический способ сделать это с помощью Rails 3:

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

ActiveRecord 4.0 и выше добавляет where.not, так что вы можете сделать это:

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

При работе с областями между таблицами я предпочитаю использовать merge, чтобы мне было проще использовать существующие области.

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

Кроме того, поскольку includes не всегда выбирает стратегию объединения, вам также следует использовать здесь references, в противном случае вы можете получить недопустимый SQL.

Foo.includes(:bar)
   .references(:bar)
   .merge(Bar.where.not(id: nil))
250 голосов
/ 23 ноября 2010

Это не ошибка в ARel, это ошибка в вашей логике.

Здесь вы хотите:

Foo.includes(:bar).where(Bar.arel_table[:id].not_eq(nil))
36 голосов
/ 06 октября 2013

Для Rails4:

Итак, вам нужно внутреннее соединение, так что вам действительно следует использовать предикат соединений:

  Foo.joins(:bar)

  Select * from Foo Inner Join Bars ...

Но для записи, еслиВы хотите, чтобы условие «NOT NULL» просто использовало предикат not:

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

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

Обратите внимание, что этот синтаксис сообщает об устаревании (он говорит о строковом фрагменте SQL, но я предполагаю, что условие хеш-функции изменяется на строковое всинтаксический анализатор?), поэтому обязательно добавьте ссылки в конце:

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

УСТАРЕВАНИЕ ПРЕДУПРЕЖДЕНИЕ: похоже, вы стремитесь загрузить таблицы (ы) (один из: ....), которые упоминаются в строковом фрагменте SQL.Например:

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

В настоящее время Active Record распознает таблицу в строке и знает, как присоединить таблицу комментариев к запросу, а не загружать комментарии в отдельном запросе.Тем не менее, выполнение этого без написания полноценного парсера SQL по своей сути ошибочно.Поскольку мы не хотим писать анализатор SQL, мы удаляем эту функциональность.Отныне вы должны явно указывать Active Record при обращении к таблице из строки:

Post.includes(:comments).where("comments.title = 'foo'").references(:comments)
22 голосов
/ 11 ноября 2016

Не уверен, что это полезно, но это то, что сработало для меня в Rails 4

Foo.where.not(bar: nil)
21 голосов
/ 08 августа 2014

С Rails 4 это просто:

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

См. Также: http://guides.rubyonrails.org/active_record_querying.html#not-conditions

...