Рельсы, где условие с использованием 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)
Ответ 5
С Rails 4 легко:
Foo.includes(:bar).where.not(bars: {id: nil})
См. также: http://guides.rubyonrails.org/active_record_querying.html#not-conditions