Рельсы, где условие с использованием NOT NIL

Используя стиль 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.

Ответ 1

Канонический способ сделать это с 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 includes не всегда выбирают стратегию присоединиться, вы должны использовать references здесь, а также, в противном случае вы можете в конечном итоге с недопустимой SQL.

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

Ответ 2

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

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

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

Ответ 3

Для Rails4:

Итак, то, что вы хотите, является внутренним соединением, поэтому вам действительно нужно использовать предикат объединения:

  Foo.joins(:bar)

  Select * from Foo Inner Join Bars ...

Но для записи, если вы хотите условие "NOT NULL", просто используйте не предикат:

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)

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

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

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

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

Ответ 4

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

Foo.where.not(bar: nil)