find () con nil cuando no hay registros


95

En mi programa de rieles actual cuando uso algo como

 user = User.find(10)

Cuando no haya un usuario con ID = 10, tendré una excepción como:

ActiveRecord::RecordNotFound: Couldn't find User with ID=10

¿Puedo obtener nulo en lugar de generar una excepción cuando hago algo como:

unless user = Challenge.find(10)
  puts "some error msg"         
end

Solo quiero obtener cero cuando no hay registros y no quiero usar begin / rescue

Gracias


Respuestas:


170

Sí, solo haz:

Challenge.find_by_id(10)

Para rieles 4 y 5:

Challenge.find_by(id: 10)

11
¡impar! Nunca hubiera imaginado que .find_by_*devolvería cero y .findno.
ddavison

Esto ha cambiado en los rieles 4, consulte esta respuesta stackoverflow.com/a/26885027/1438478 para conocer la nueva forma de encontrar un elemento por un atributo específico.
Fralcon

Encontré un problema extraño con Rails 4.2 en el que cuando pasa un hash como 'x' Something.find_by(id: x), se crea una declaración SQL con todos los pares de atributo / valor del hash como parte de la cláusula WHERE. Me parece un error de Rails.
Tilo

Rails (3, 4 o 5) genera find_by_...buscadores dinámicos para cada atributo que tiene un modelo incluido :id. Por lo tanto, Challenge.find_by_id(10)debería funcionar independientemente de la versión de Rails.
Arta

Como lo especifica @MohamedIbrahim a continuación, también puede hacer:Challenge.find(10) rescue nil
Hallgeir Wilhelmsen

31

En Rails 4, los buscadores dinámicos, como el find_by_idque se usó en la respuesta aceptada, quedaron obsoletos.

En el futuro, debe usar la nueva sintaxis:

Challenge.find_by id: 10

4
En caso de que alguien más esté confundido por esto como yo: Challenge.find_by(id: 10)es la otra forma de escribir esto
Devin Howard

14

puede hacer esto un poco pirateado, simplemente use la interfaz de consulta ActiveRecord.

esto devolverá nil, en lugar de generar una excepción

  User.where(:id => 10).first

Una razón para usar esto en lugar de hacerlo find_by_ides que es portátil de Rails 3 a 4. En Rails 4, lo es find_by(:id => 10).
Gene

5

¿Por qué no capta simplemente la excepción? Su caso se ve exactamente como se hicieron las excepciones:

begin
  user = User.find(10)
rescue ActiveRecord::RecordNotFound
  puts "some error msg"
end

Si desea recuperarse del error en el bloque de rescate (por ejemplo, estableciendo un usuario de marcador de posición (patrón nulo)), puede continuar con su código debajo de este bloque. De lo contrario, puede poner todo su código para el "caso feliz" en el bloque entre "comenzar" y "rescate".


Por cierto: ni siquiera necesita el begin…endbloque, si ya tiene un bloque como un método de controlador. En ese caso, la única línea adicional que necesita es la rescuelínea. Mucho más elegante y más fácil de manejar que comprobar nilcon una ifdeclaración.
Morgler


4

Para aquellos que luchan con mongoid , resulta que ambos métodos findy find_bygenerarán una excepción, ¡sin importar su versión de rieles!

Hay una opción (a saber, raise_not_found_error ) que se puede establecer en falso, pero cuando falsey hace que el findmétodo no genere una excepción también.

Por lo tanto, la solución para los usuarios de mongoides es el código repugnante:

User.where(id: 'your_id').first # argghhh

¿Qué opinas de la solución de rescate cero de mohamed-ibrahim? .where(email: params[:email]).firstMe parece más elegante que a mí.
Wylliam Judd

1
Prefiero no usar esa rescuesintaxis, ya que puede ocultar problemas como errores tipográficos
Cristiano Mendonça

Terminé usando la solución de @ morgler.
Wylliam Judd

2

tan simple como:

user = User.find(10) rescue nil

1
Preferiría ser más específico sobre qué error se espera rescatar, ActiveRecord :: RecordNotFound en este caso. Como señaló en esta respuesta @morgler
luizrogeriocn

2
Personalmente, encuentro que esta es la mejor respuesta. Ya le estoy diciendo a mi código qué hacer si el usuario no se encuentra enif user...else
Wylliam Judd

0

Puede usar find_by con el atributo requerido (en su caso, el id), esto devolverá nil en lugar de dar un error si no se encuentra el id dado.

user = Challenge.find_by_id(id_value)

o puede usar el nuevo formato:

user = Challenge.find_by id: id_value

También puede usar where, pero debe saber que where devuelve una relación de registro activa con cero o más registros que debe usar primero para devolver solo un registro o nulo en caso de que regresen cero registros.

user = Challenge.where(id: id_value).first
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.