2011-02-11 10 views

Respuesta

51

Este es el comportamiento esperado. Creo que David lo explica mejor, así que aquí hay una cita de Ruby, S., Thomas, D. & Hansson, D.H., 2009. Agile Web Development with Rails, Tercera Edición Tercera Edición., Pragmatic Bookshelf (p.330).

Cuando se utiliza un buscador impulsado por claves primarias, que está buscando un registro en particular . Espera que exista . Una llamada a Person.find (5) es según nuestro conocimiento de la tabla de personas. Queremos la fila con una identificación de 5. Si esta llamada no es exitosa -si el registro con la identificación de 5 ha sido destruido-estamos en una situación excepcional . Esto obliga a aumentar de una excepción, por lo que Rails aumenta RecordNotFound.

Por otro lado, los buscadores que usan criterios para buscar están buscando una coincidencia. Por lo tanto, Person.find (: first, : conditions => "name = 'Dave'") es el equivalente de decirle a la base de datos (como una casilla negra) "Dame la primera persona fila que tiene el nombre Dave. "Este exhibe un enfoque claramente diferente para la recuperación; no estamos seguros por adelantado de que obtendremos un resultado. Es completamente posible que el conjunto de resultados esté vacío. Por lo tanto, devuelve nil en el caso de los buscadores que buscan una fila y una matriz vacía para los buscadores que buscan muchas filas es la respuesta natural, no excepcional.

+0

lo explica mejor .. – rubyprince

+1

Si desea que la excepción sea lanzada en find_by_attributes sabores de los métodos de búsqueda, puede utilizar la explosión! versión del método. Por ejemplo, Model.find_by_category! (A_category_value) arrojará RecordNotFound si no se encuentra ninguna coincidencia. Encontré esto como DRY en escenarios como los controladores RESTful, donde tengo un controlador de error común para la excepción y quiero que mis acciones se comporten de manera consistente cuando no se encuentra un recurso que coincida con los parámetros especificados. –

+6

La confusión sobre esto se repite con todos los que vienen a Rails y obtienen una excepción. La confusión/sorpresa se debe a que 'find' es un verbo suave, y no establece explícitamente la precisión o el conocimiento previo de la existencia. Por supuesto, ahora tenemos la decisión, pero es una pregunta que se formulará siempre que nuevas personas comiencen a usar Rails. – ocodo

4

arrojar la excepción es el comportamiento esperado.

De hecho, en el curso normal de los eventos, si deja que la excepción no se controle, el servidor de los raíles devolverá el error 404 página no encontrada correcta.

si lo desea para que vuelva a cero se puede tomar por sí mismo:

begin 
    @model = Model.find(id_provided) 
rescue ActiveRecord::RecordNotFound => e 
    @model = nil 
end 
+1

Thanks..I también encontró el error y me encontré es molesto ... Podemos usar 'Model.find_by_id (1)' pero lo encuentro torpe. – rubyprince

0

Puede verificar si el registro existe antes de ir a buscarlo.

@model = Model.find(id) if Model.exists?(id) 
+7

esto se resolverá en 2 consultas que no es ideal. – VelLes

22

Si realmente no quiere la excepción, puede utilizar find_by_id:

# @user = User.find(params[:id]) # original code 
@user = User.find_by_id(params[:id]) 
if @user 
    # found! 
else 
    # not found 
end 

Esto debería ser más rápido que un cheque por separado exists?.

EDITAR: Tenga en cuenta que, como comentó @Miguelgraz, en Rails 4 debería decir User.find_by(id: params[:id]). La misma funcionalidad, pero ahora la implementación no necesitará method_missing.

+0

sí ... He mencionado eso en el comentario a la respuesta de Kalendae ... – rubyprince

+1

Esto está obsoleto en los rieles 4, consulte esta otra respuesta http://stackoverflow.com/a/26885027/645223 – Miguelgraz

1

Si desea que se arroje la excepción en find_by_attributes sabores de los métodos del buscador, puede usar el bang! versión del método.

Por ejemplo,

Model.find_by_category!(a_category_value) 

arrojará RecordNotFound si no se encuentra ninguna coincidencia.

Encontré esto como DRY en escenarios como los controladores RESTful, donde tengo un controlador de error común para la excepción y quiero que mis acciones se comporten de manera consistente cuando no se encuentra un recurso que coincida con los parámetros dados.

0

Carriles 4 Método

if user = User.find_by(id: params[:id]) 
    #do something with user 
else 
    #throw error or redirect 
    raise ActiveRecord::RecordNotFound 
end 
0

Puede utilizar 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 identificador dado.

Model.find_by_id(id_value) 

También es posible usar donde pero hay que saber que en relación devolver un registro activo con cero o más registros es necesario utilizar primero para devolver sólo un registro o nula en caso de retorno a cero registros.

Model.where(id: id_value).first 
0

Usted puede simplemente utilizar:

user = User.find(10) rescue nil 
Cuestiones relacionadas