2011-09-08 9 views
12

Quiero atrapar la acción de error desconocido en Rails 3, que muestra "Desconocido Acción" error en el desarrollo y la 404.html en la producción. He intentado poner este controlador rescue_from en mi ApplicationController (y también en un controlador real, por si acaso), pero todavía ver el error feo.Catch Acción desconocida en Rails 3 por 404

tengo cosas personalizada en el 404, y no puede haber archivo .html llanura.

Mi ruta:

match '/user/:id/:action', controller: 'users' 

La URL que estoy acceder a: /user/elado/xxx

El código rescue_from:

rescue_from AbstractController::ActionNotFound, :with => :action_not_found 

def action_not_found 
    render text: "action_not_found" 
end 

El error en el explorador:

Unknown action 

The action 'xxx' could not be found for UsersController 

Y en la consola:

Started GET "/user/elado/xxx" for 127.0.0.1 at 2011-09-07 19:16:27 -0700 

AbstractController::ActionNotFound (The action 'xxx' could not be found for UsersController): 

ha intentado también rescue_from ActionController::UnknownAction.

¿Alguna sugerencia? Gracias!

Respuesta

14

rescue_from fue ligeramente rota cuando Rails 3 salieron (siendo roto en 3.1 también). Básicamente no se puede:

rescue_from ActionController::RoutingError 

más. Ver here.

La solución, por ahora, es lo que recomienda hamiltop. Use una ruta de atrapar todas las que corresponda a su ruta de "error de enrutamiento". Asegúrate de ponerlo al final de tu archivo config \ routes.rb para que se procese al final.

# Any routes that aren't defined above here go to the 404 
match "*a", :to => "application#routing_error" 

def routing_error 
    render "404", :status => 404 
end 

Nota: Este método tiene un inconveniente importante. Si usa un motor como Jammit o idee la captura, la ruta hará que Rails ignore las rutas del motor.

Si no está utilizando un motor que tiene su propia ruta, entonces debería estar bien. Sin embargo, si utiliza un motor que define sus propias rutas, vea la respuesta de @arikfr.

+0

El siguiente enlace proporciona una buena idea, también proporciona un ejemplo de cómo manejar mejor la excepción (3.2 o superior). http://geekmonkey.org/articles/29-exception-applications-in-rails-3-2 – Agustin

0

Ha intentado una captura toda la ruta?

http://railscasts.com/episodes/46-catch-all-route

La ruta comodín que usted está al corriente usando es una mala idea (tm).

Yo recomendaría la definición de las rutas que le interesan, y luego hacer un cajón de sastre como la última línea de routes.rb (rutas definidas por primera vez en Trump routes.rb posteriores definiciones). Luego puede renderizar la página que desee (y especificar el código de estado 404).

Editar: Si realmente desea utilizar su enfoque actual ... (aunque esto parece que podría ser obsoleta)

def rescue_action (excepción) caso excepción cuando ActionNotFound, a continuación, UnknownAction # manejar estas excepciones aquí demás súper final final

+0

En realidad, estoy usando la opción atrapar todas las rutas para otra cosa, pero en realidad podría agregar solo la acción disponible real en lugar de: acción. Gracias. ¿Pero estoy haciendo algo mal con el 'rescue_from'? Parece que debería funcionar ... – elado

+0

Gracias, aunque 'def rescue_action (excepción); excepción de caso; cuando ActionController :: UnknownAction, AbstractController :: ActionNotFound luego procesa texto: "404"; else render texto: "otra excepción"; fin; fin' en ApplicationController o UsersController no funcionó. – elado

9

Usar una ruta catch all para manejar errores 404 (como sugirió @Seth Jackson) tiene un inconveniente importante: si usa cualquier motor Rails que defina sus propias rutas (como Jammit) se ignorarán sus rutas.

Una solución mejor y más compatible sería usar un middleware Rack que atrapará errores 404. En uno de mis proyectos, he implementado un middleware de Rack que informa estos errores a Hoptoad. He basado mi implementación en este: https://github.com/vidibus/vidibus-routing_error, pero en vez de invocar mi aplicación Rails nuevamente para manejar el error 404, lo hago en el middleware de Rack y dejo que nginx muestre la página 404.

+0

Buena captura. Me había olvidado de esto. Lo he notado con otros motores (Devise) también. Agregaré una nota sobre esto a mi respuesta. –

1

Si realmente quiere rescatar AbstractController::ActionNotFound en un controlador, puede intentar algo como esto:

class UsersController < ApplicationController 

    private 

    def process(action, *args) 
    super 
    rescue AbstractController::ActionNotFound 
    respond_to do |format| 
     format.html { render :404, status: :not_found } 
     format.all { render nothing: true, status: :not_found } 
    end 
    end 


    public 

    # actions must not be private 

end 

Esto reemplaza el método de AbstractController::Baseprocess que eleva AbstractController::ActionNotFound (ver source).