2011-09-08 16 views
12

Chcę złapać nieznany błąd działania w Rails 3, który pokazuje błąd "Nieznana akcja" podczas tworzenia i 404.html podczas produkcji. Próbowałem umieścić ten rescue_from Handler na moim ApplicationController (a także na faktycznym kontrolerze, na wszelki wypadek), ale nadal widzę brzydki błąd.Złap nieznaną akcję w Railsach 3 dla niestandardowego 404

Mam niestandardowe rzeczy na 404, i to nie może być zwykły plik .html.

Moja trasa:

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

URL mam dostępu: /user/elado/xxx

Kod rescue_from:

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

def action_not_found 
    render text: "action_not_found" 
end 

Błąd w przeglądarce:

Unknown action 

The action 'xxx' could not be found for UsersController 

A w konsoli:

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): 

Próbowano również rescue_from ActionController::UnknownAction.

Wszelkie sugestie? Dzięki!

Odpowiedz

14

rescue_from został lekko uszkodzony podczas Rails 3 wyszedł (wciąż łamane w 3.1 też). Zasadniczo nie można już:

rescue_from ActionController::RoutingError 

już. Zobacz here.

Rozwiązanie, na razie, jest tym, co zaleca hamiltop. Zastosuj funkcję przechwytywania całej trasy prowadzącej do trasy "routing error". Upewnij się, że umieściłeś go na końcu pliku config \ routes.rb, aby był on przetwarzany jako ostatni.

# 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 

Uwaga: Metoda ta ma jednak jedną wadę. Jeśli używasz silnika, takiego jak Jammit lub Devise, wszystkie elementy, które zostaną trasowane, spowodują, że Railsy zignorują trasy silnika.

Jeśli nie korzystasz z silnika, który ma własne trasy, powinieneś być w porządku. Jeśli jednak używasz silnika, który definiuje własne trasy, patrz odpowiedź @ arikfr.

+0

Poniższy link zapewnia dobry wgląd, a także podaje przykład lepszego radzenia sobie z wyjątkami (3.2 lub wyżej). http://geekmonkey.org/articles/29-exception-applications-in-rails-3-2 – Agustin

0

Czy próbowałeś złapać całą trasę?

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

Trasa wieloznaczny, że jesteś obecny przy użyciu jest zły pomysł (tm).

Zalecam zdefiniowanie tras, które Cię interesują, a następnie wykonanie catchall jako ostatniej linii routes.rb (trasy zdefiniowane jako pierwsze w routes.rb atrybuty późniejszych definicji). Następnie możesz renderować dowolną żądaną stronę (i podać kod statusu 404).

Edycja: Jeśli naprawdę chcesz korzystać z obecnego podejścia ... (chociaż wydaje się to mogło być przestarzałe)

def rescue_action (wyjątek) przypadek, gdy wyjątek ActionNotFound, UnknownAction następnie # obsługiwać te Wyjątkiem tutaj inny Super koniec koniec

+0

W rzeczywistości używam catch all route dla czegoś innego, ale mogę dodać tylko rzeczywistą dostępną akcję zamiast: action. Dzięki. Ale czy robię coś złego w 'rescue_from'? Wygląda na to, że powinno działać ... – elado

+0

Dzięki, choć 'def rescue_action (wyjątek); wyjątek przypadku; gdy ActionController :: UnknownAction, AbstractController :: ActionNotFound wyświetla tekst: "404"; else render text: "inny wyjątek"; koniec; Koniec' w ApplicationController lub UsersController nie działa. – elado

9

Korzystanie z funkcji przechwytywania całej trasy do obsługi erozów 404 (jak sugeruje @Seth Jackson) ma jedną poważną wadę: jeśli użyjesz silników Railsowych, które definiują własne trasy (takie jak Jammit), ich trasy zostaną zignorowane.

Lepszym i bardziej zgodnym rozwiązaniem byłoby użycie oprogramowania pośredniczącego typu Rack, które wykryje 404 błędy. W jednym z moich projektów zaimplementowałem takie oprogramowanie pośredniczące Rack, które zgłasza te błędy do Hoptoad. Oparłem moją implementację na tym: https://github.com/vidibus/vidibus-routing_error, ale zamiast ponownie wywoływać moją aplikację Rails, aby obsłużyć błąd 404, robię to w oprogramowaniu pośredniczącym Rack i pozwolę nginxowi na wyświetlenie strony 404.

+0

Przyjemny połów. Zapomniałem o tym. Zauważyłem to również w innych silnikach (Devise). Dodam notatkę na ten temat do mojej odpowiedzi. –

1

Jeśli naprawdę chcą ratować AbstractController::ActionNotFound w kontrolerze, możesz spróbować czegoś takiego:

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 

Ten przesłania metodę process z AbstractController::Base który podnosi AbstractController::ActionNotFound (patrz source).

Powiązane problemy