ruby on rails - rails - ¿Cómo devolver una relación vacía de ActiveRecord?
rails associations (9)
Si tengo un ámbito con un lambda y toma un argumento, dependiendo del valor del argumento, puedo saber que no habrá coincidencias, pero aún quiero devolver una relación, no una matriz vacía:
scope :for_users, lambda { |users| users.any? ? where("user_id IN (?)", users.map(&:id).join('','')) : [] }
Lo que realmente quiero es un método "ninguno", lo opuesto a "todos", que devuelve una relación que aún puede ser encadenada, pero que resulta en una consulta cortocircuitada.
Viniendo en rieles 4
En Rails 4, se devolverá un ActiveRecord::NullRelation
de llamadas como Post.none
.
Ni esto, ni los métodos encadenados, generarán consultas a la base de datos.
Según los comentarios:
El ActiveRecord :: NullRelation devuelto se hereda de la relación e implementa el patrón de objeto nulo. Es un objeto con un comportamiento nulo definido y siempre devuelve una matriz de registros vacía sin consultar la base de datos.
Consulte el código fuente .
Ahora hay un mecanismo "correcto" en Rails 4:
>> Model.none
=> #<ActiveRecord::Relation []>
Creo que prefiero la forma en que se ve a las otras opciones:
scope :none, limit(0)
Conduciendo a algo como esto:
scope :users, lambda { |ids| ids.present? ? where("user_id IN (?)", ids) : limit(0) }
Es posible y eso es:
scope :for_users, lambda { |users| users.any? ? where("user_id IN (?)", users.map(&:id).join('','')) : User.none }
http://apidock.com/rails/v4.0.2/ActiveRecord/QueryMethods/none
Corrígeme si me equivoco.
Puedes agregar un alcance llamado "ninguno":
scope :none, where(:id => nil).where("id IS NOT ?", nil)
Eso te dará un ActiveRecord vacío :: Relación
También puede agregarlo a ActiveRecord :: Base en un inicializador (si lo desea):
class ActiveRecord::Base
def self.none
where(arel_table[:id].eq(nil).and(arel_table[:id].not_eq(nil)))
end
end
Hay muchas maneras de obtener algo como esto, pero ciertamente no es lo mejor para mantener en una base de código. He utilizado el alcance: ninguno al refactorizar y encontrar que necesito garantizar un ActiveRecord :: Relation vacío por un corto tiempo.
También hay variantes, pero todas estas están solicitando db
where(''false'')
where(''null'')
Una solución más portátil que no requiere una columna "id" y no asume que no habrá una fila con una id de 0:
scope :none, where("1 = 0")
Todavía estoy buscando una forma más "correcta".
Utilizar ámbito:
scope :for_users, lambda { |users| users.any? ? where("user_id IN (?)", users.map(&:id).join('','')) : scoped }
Pero, también puedes simplificar tu código con:
scope :for_users, lambda { |users| where(:user_id => users.map(&:id)) if users.any? }
Si desea un resultado vacío, use esto (elimine la condición if):
scope :for_users, lambda { |users| where(:user_id => users.map(&:id)) }
scope :none, limit(0)
Es una solución peligrosa porque su alcance podría estar encadenado.
Usuario.none.first
Volverá el primer usuario. Es más seguro de usar
scope :none, where(''1 = 0'')