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


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

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

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

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

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

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

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

5 328

5 ответов:

канонический способ сделать это с 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))

Я больше не рекомендуем использовать Squeel для этого, поскольку он не всегда имеет полный рабочий день сопровождающего, и это зависит от частных API, которые вызывают частые изменения взлома.

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

что вы хотите здесь:

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

Для Rails4:

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

  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 парсер, мы удаляем это функциональность. Отныне вы должны явное указание активной записи при ссылке на таблицу из a строка:

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

с рельсами 4 это легко:

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

Смотрите также: http://guides.rubyonrails.org/active_record_querying.html#not-conditions

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

Foo.where.not(bar: nil)