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

Eqbal
fuente

Respuestas:

170

Sí, solo haz:

Challenge.find_by_id(10)

Para rieles 4 y 5:

Challenge.find_by(id: 10)
apneadiving
fuente
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
hattila91
fuente
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
gorro
fuente
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".

morgler
fuente
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

Puedes probar esto Challenge.exists?(10)

Tonymarschall
fuente
7
será una solicitud adicional de sql
fl00r
Aun así, creo que esto es mejor para las pruebas
SomeSchmo
úselo
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
Cristiano Mendonça
fuente
¿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
mohamed-ibrahim
fuente
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
Alanoud solo
fuente