Используя стиль рельсов 3, как бы я написал противоположное:
Foo.includes(:bar).where(:bars=>{:id=>nil})
Я хочу найти, где id не равно null. Я пробовал:
Foo.includes(:bar).where(:bars=>{:id=>!nil}).to_sql
Но это возвращает:
=> "SELECT \"foos\".* FROM \"foos\" WHERE (\"bars\".\"id\" = 1)"
Это определенно не то, что мне нужно, и почти похоже на ошибку в AREL.
Канонический способ сделать это с помощью 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 })
Я больше не рекомендую использовать Squeel для этого, так как у него не всегда есть постоянный сопровождающий, и это зависит от частного API, которые вызывают частые нарушения.
rails undefined method 'not_eq' for :confirmed_at:Symbol
..
Это не ошибка в AREL, это ошибка в вашей логике.
Здесь вы хотите:
Foo.includes(:bar).where(Bar.arel_table[:id].not_eq(nil))
true
, что является логическим значением. :id => true
возвращает вам id = 1
в SQLese.
Для 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)
references
звонок помог мне!
С Rails 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)
!nil
оценивает значениеtrue
в Ruby, а ARel переводит значениеtrue
в1
в запросе SQL. Таким образом, сгенерированный запрос на самом деле является тем, что вы просили - это не ошибка ARel.