relaciones rails llaves foreign foraneas ruby-on-rails activerecord relation

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) }



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'')