¿Cómo devolver una relación ActiveRecord vacía?


Si tengo un ámbito con una lambda y toma un argumento, dependiendo del valor del argumento, podría saber que no habrá ninguna coincidencia, pero aún quiero devolver una relación, no un array vacío:

scope :for_users, lambda { |users| users.any? ? where("user_id IN (?)", users.map(&:id).join(',')) : [] }

Lo que realmente quiero es un método "none", lo opuesto a "all", que devuelva una relación que todavía se puede encadenar, pero que resulte en un cortocircuito de la consulta.

Author: dzajic, 2011-02-02

9 answers

Ahora hay un mecanismo "correcto" en Rails 4:

>> Model.none 
=> #<ActiveRecord::Relation []>
 403
Author: steveh7,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-09 02:25:45

Una solución más portátil que no requiere una columna "id"y no asume que no habrá una fila con un id de 0:

scope :none, where("1 = 0")

Todavía estoy buscando una manera más "correcta".

 74
Author: steveh7,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-16 04:12:59

Puede agregar un ámbito llamado"none":

scope :none, where(:id => nil).where("id IS NOT ?", nil)

Eso te dará un ActiveRecord::Relation vacío

También puedes añadirlo a ActiveRecord:: Base en un inicializador (si quieres):

class ActiveRecord::Base
 def self.none
   where(arel_table[:id].eq(nil).and(arel_table[:id].not_eq(nil)))
 end
end

Muchas maneras de obtener algo como esto, pero ciertamente no es lo mejor para mantener en una base de código. He usado el scope: none al refactorizar y encontrar que necesito garantizar una relación vacía ActiveRecord:: por un corto tiempo.

 42
Author: Brandon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-21 06:49:21

Viene en Raíles 4

En Rails 4, se devolverá un ActiveRecord::NullRelation encadenable desde llamadas como Post.none.

Ni él, ni los métodos encadenados, generarán consultas a la base de datos.

Según los comentarios:

El ActiveRecord::NullRelation devuelto hereda de Relation and implements the Null Object pattern. Es un objeto con comportamiento null definido y siempre devuelve una matriz vacía de registros sin quering la base de datos.

Véase el código fuente .

 42
Author: Nathan Long,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-23 19:28:45
scope :none, limit(0)

Es una solución peligrosa porque su alcance podría estar encadenado.

Usuario.ninguno.primero

Devolverá el primer usuario. Es más seguro usar

scope :none, where('1 = 0')
 24
Author: bbrinck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-12 16:00:47

Creo que prefiero la forma en que esto se ve a las otras opciones:

scope :none, limit(0)

Que conduce a algo como esto:

scope :users, lambda { |ids| ids.present? ? where("user_id IN (?)", ids) : limit(0) }
 14
Author: Alex,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-22 13:59:31

Use ámbito de aplicación:

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)) }
 3
Author: Pan Thomakos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-02-04 05:33:47

También hay variantes, pero todas estas están haciendo una solicitud a db

where('false')
where('null')
 1
Author: fmnoise,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-17 12:34:21

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.

 0
Author: ilgam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-13 14:03:50