Carriles donde la condición NO usando NIL
-
27-09-2019 - |
Pregunta
El uso de los carriles de 3 estilo de cómo iba a escribir lo contrario de:
Foo.includes(:bar).where(:bars=>{:id=>nil})
Quiero encontrar donde id no es nula. Probé:
Foo.includes(:bar).where(:bars=>{:id=>!nil}).to_sql
Pero que los rendimientos:
=> "SELECT \"foos\".* FROM \"foos\" WHERE (\"bars\".\"id\" = 1)"
Esto definitivamente no es lo que necesito, y casi parece un error en Arel.
Solución
La forma canónica de hacer esto con Rails 3:
Foo.includes(:bar).where("bars.id IS NOT NULL")
ActiveRecord 4.0 y superior añade where.not
para que pueda hacer esto:
Foo.includes(:bar).where.not('bars.id' => nil)
Foo.includes(:bar).where.not(bars: { id: nil })
Cuando se trabaja con alcances entre tablas, prefiero apalancamiento merge
de modo que pueda utilizar ámbitos existentes con mayor facilidad.
Foo.includes(:bar).merge(Bar.where.not(id: nil))
Además, dado que includes
no siempre elige una estrategia de combinación, se debe utilizar references
aquí también , de lo contrario puede terminar con SQL válido.
Foo.includes(:bar)
.references(:bar)
.merge(Bar.where.not(id: nil))
Otros consejos
No es un error en Arel, que es un error en la lógica.
Lo que se quiere aquí es:
Foo.includes(:bar).where(Bar.arel_table[:id].not_eq(nil))
Para Rails4:
Por lo tanto, lo que está queriendo es una combinación interna, lo que realmente debe utilizar sólo las uniones de predicados:
Foo.joins(:bar)
Select * from Foo Inner Join Bars ...
Sin embargo, para el registro, si quieres un "NO NULO" afección simplemente no utilizar el predicado:
Foo.includes(:bar).where.not(bars: {id: nil})
Select * from Foo Left Outer Join Bars on .. WHERE bars.id IS NOT NULL
Tenga en cuenta que esta sintaxis reporta una depreciación (se habla de un fragmento de cadena SQL, pero supongo que la condición de hash se cambia a cadena en el analizador?), Así que asegúrese de agregar las referencias al final:
Foo.includes(:bar).where.not(bars: {id: nil}).references(:bar)
Deprecation ADVERTENCIA: Parece que usted está ansioso mesa de carga (s) (uno de: ....) que se hace referencia en un fragmento de cadena SQL. Por ejemplo:
Post.includes(:comments).where("comments.title = 'foo'")
Actualmente, Active Record reconoce la mesa en la cadena, y sabe Para unirse a la mesa de comentarios a la consulta, en lugar de cargar los comentarios en una consulta separada. Sin embargo, hacer esto sin tener que escribir un lleno-soplado intérprete de SQL está viciado. Dado que no queremos escribir una consulta SQL analizador, vamos a eliminar esta funcionalidad. A partir de ahora, debe decirle explícitamente Registro Activo cuando se hace referencia a una tabla de una cadena:
Post.includes(:comments).where("comments.title = 'foo'").references(:comments)
No estoy seguro de que esto sea útil, pero esto lo que funcionó para mí en los carriles 4
Foo.where.not(bar: nil)
Con los carriles 4 es fácil:
Foo.includes(:bar).where.not(bars: {id: nil})
Consulte también: http://guides.rubyonrails.org/active_record_querying.html#not-conditions