2013-08-21 16 views
15

Ich bin ein Ruby on Rails API erstellen mit Ruby 2.0 und Rails 4.0. Meine App ist fast ausschließlich eine JSON-API. Wenn also ein Fehler auftritt (500, 404), möchte ich diesen Fehler erfassen und eine gut formatierte JSON-Fehlermeldung zurückgeben.Benutzerdefinierte Fehlerbehandlung mit Rails 4.0

Ich habe this versucht, und auch:

rescue_from ActionController::RoutingError, :with => :error_render_method 

def error_render_method 
    puts "HANDLING ERROR" 
    render :json => { :errors => "Method not found." }, :status => :not_found 
    true 
end 

In meiner Application.

Keine von beiden macht den Trick (die Ausnahmen werden überhaupt nicht erfasst). My Googling zeigt, dass sich dies zwischen 3.1, 3.2 geändert hat und ich kann keine gute Dokumentation finden, wie dies in Rails 4.0 gemacht wird.

Jeder weiß?

bearbeiten Hier ist der Stack-Trace, wenn ich auf eine 404-Seite gehen:

Started GET "/testing" for 127.0.0.1 at 2013-08-21 09:50:42 -0400 

ActionController::RoutingError (No route matches [GET] "/testing"): 
actionpack (4.0.0) lib/action_dispatch/middleware/debug_exceptions.rb:21:in `call' 
actionpack (4.0.0) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call' 
railties (4.0.0) lib/rails/rack/logger.rb:38:in `call_app' 
railties (4.0.0) lib/rails/rack/logger.rb:21:in `block in call' 
activesupport (4.0.0) lib/active_support/tagged_logging.rb:67:in `block in tagged' 
activesupport (4.0.0) lib/active_support/tagged_logging.rb:25:in `tagged' 
activesupport (4.0.0) lib/active_support/tagged_logging.rb:67:in `tagged' 
railties (4.0.0) lib/rails/rack/logger.rb:21:in `call' 
actionpack (4.0.0) lib/action_dispatch/middleware/request_id.rb:21:in `call' 
rack (1.5.2) lib/rack/methodoverride.rb:21:in `call' 
rack (1.5.2) lib/rack/runtime.rb:17:in `call' 
activesupport (4.0.0) lib/active_support/cache/strategy/local_cache.rb:83:in `call' 
rack (1.5.2) lib/rack/lock.rb:17:in `call' 
actionpack (4.0.0) lib/action_dispatch/middleware/static.rb:64:in `call' 
railties (4.0.0) lib/rails/engine.rb:511:in `call' 
railties (4.0.0) lib/rails/application.rb:97:in `call' 
rack (1.5.2) lib/rack/lock.rb:17:in `call' 
rack (1.5.2) lib/rack/content_length.rb:14:in `call' 
rack (1.5.2) lib/rack/handler/webrick.rb:60:in `service' 
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/webrick/httpserver.rb:138:in `service' 
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/webrick/httpserver.rb:94:in `run' 
/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/webrick/server.rb:295:in `block in start_thread' 


Rendered /Library/Ruby/Gems/2.0.0/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.0ms) 
Rendered /Library/Ruby/Gems/2.0.0/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/routes/_route.html.erb (2.9ms) 
Rendered /Library/Ruby/Gems/2.0.0/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/routes/_route.html.erb (0.9ms) 
Rendered /Library/Ruby/Gems/2.0.0/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/routes/_table.html.erb (1.1ms) 
Rendered /Library/Ruby/Gems/2.0.0/gems/actionpack-4.0.0/lib/action_dispatch/middleware/templates/rescues/routing_error.erb within rescues/layout (38.3ms) 

Ich glaube nicht, ich will es so weit überhaupt erhalten, soll etwas fangen und gibt die entsprechende json Fehlerreaktion.

+0

Hmmmm, das könnte tatsächlich funktionieren, wie ich es Setup habe ... Lass mich es noch mehr testen. –

Antwort

0

dies versuchen, wenn Sie auf alle Arten von Fehlern auf die gleiche Weise reagieren wollen

rescue_from StandardError, :with => :error_render_method

Wenn Sie dieses Verhalten nicht Modus in Ihrer Entwicklung möchten, fügen Sie den obigen Code unter

unless Rails.application.config.consider_all_requests_local

+1

Gut zu wissen, aber es sieht so aus, als würde der Fehler überhaupt nicht aufgefangen (ich habe einen Stack-Trace hinzugefügt). Meine "error_render_method" wird nie aufgerufen. –

+0

Ich benutze Schienen 3.2.13 und es funktioniert für mich. Möglicherweise haben sie etwas in Schienen geändert 4 – usha

+0

Dies würde in wenigen verschiedenen Fällen nicht aufgerufen werden, wenn Sie es in Ihrem ActionController falsch enthalten. Aus der Dokumentation: "Der Handler der ersten Klasse, für den exception.is_a? (Klass) wahr ist, ist derjenige, der aufgerufen wird, falls überhaupt" – WattsInABox

9

dies funktioniert in rails4, so können Sie direkt alle Fehler verwalten: zum Beispiel können Sie error_info als json rendern, wenn ein Fehler von einem API-Aufruf auftritt.

application_controller.rb

class ApplicationController < ActionController::Base 
    protect_from_forgery 


    # CUSTOM EXCEPTION HANDLING 
    rescue_from StandardError do |e| 
    error(e) 
    end 

    def routing_error 
    raise ActionController::RoutingError.new(params[:path]) 
    end 

    protected 

    def error(e) 
    #render :template => "#{Rails::root}/public/404.html" 
    if env["ORIGINAL_FULLPATH"] =~ /^\/api/ 
    error_info = { 
     :error => "internal-server-error", 
     :exception => "#{e.class.name} : #{e.message}", 
    } 
    error_info[:trace] = e.backtrace[0,10] if Rails.env.development? 
    render :json => error_info.to_json, :status => 500 
    else 
     #render :text => "500 Internal Server Error", :status => 500 # You can render your own template here 
     raise e 
    end 
    end 

    # ... 

end 

routes.rb

MyApp::Application.routes.draw do 

    # ... 

    # Any other routes are handled here (as ActionDispatch prevents RoutingError from hitting ApplicationController::rescue_action). 
    match "*path", :to => "application#routing_error", :via => :all 
end 
16

Die Anfrage Ihre App nicht einmal trifft.

Sie benötigen einen catchall Route zu definieren, so Rails wird die Anfrage an Ihre App nicht angezeigt werden einen Fehler (in Entwicklung) oder machen die Öffentlichkeit/404.html Seite (in der Produktion)

Ändern Sie bitte Ihre Routen senden. rb-Datei gehören die folgenden

match "*path", to: "errors#catch_404", via: :all 

Und in Ihrem Controller

class ErrorsController < ApplicationController 

    def catch_404 
    raise ActionController::RoutingError.new(params[:path]) 
    end 
end 

Und Ihre rescue_from sollte dann den Fehler abzufangen.

+1

Möglicherweise möchten Sie "get" in Routen zu 'match' ändern, da dies auch für andere Anfrage-Methoden passieren könnte. – dylanfm

+0

Wahr, bearbeitet. Vielen Dank! – silasjmatson

+1

Rails 4 werden Sie daran erinnern, "Ihre Aktion sowohl GET als auch POST zu zeigen, [by] add [ing]' via: [: get,: post] '" - denken Sie daran, das auch zu tun! :) – sameers

14

Nach ein paar Variationen ich versucht, auf diese als die einfachste Art und Weise zu regeln haben die API 404s zu handhaben:

# Passing request spec 
describe 'making a request to an unrecognised path' do 
    before { host! 'api.example.com' } 
    it 'returns 404' do 
    get '/nowhere' 
    expect(response.status).to eq(404) 
    end 
end 

# routing 
constraints subdomain: 'api' do 
    namespace :api, path: '', defaults: { format: 'json' } do 
    scope module: :v1, constraints: ApiConstraints.new(1) do 
     # ... actual routes omitted ... 
    end 
    match "*path", to: -> (env) { [404, {}, ['{"error": "not_found"}']] }, via: :all 
    end 
end 
+0

+1 für das Speichern in der Routes-Datei und Hinzufügen eines Tests. Ich habe das mehr oder weniger wortgetreu in meiner App verwendet, danke! –

1

ich die 404 verwendet.HTML aus dem öffentlichen Ordner und das ist in der Entwicklungsumgebung.
Ich habe tatsächlich die Antwort aus:

Allerdings habe ich ein kleines Experiment tat auf welche Teile des Codes tatsächlich funktioniert. Hier sind die Teile des Codes, die ich nur hinzugefügt habe.

config/routes.rb

Rails.application.routes.draw do 
    // other routes 
    match "*path", to: "application#catch_404", via: :all 
end 

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base 
    def catch_404 
     render :file => 'public/404.html', :status => :not_found 
    end 
end 

Wird keine Kommentare und Erklärungen zu schätzen wissen, warum sind einige der ursprünglichen nötig sind, um . Zum Beispiel mit dieser Codezeile

raise ActionController::RoutingError.new(params[:path]) 

und dieses

rescue_from ActionController::RoutingError, :with => :error_render_method 

Da rescue_from und raise ActionController::RoutingError scheinen die beliebte Antwort von den älteren Rails-Versionen zu sein.

Verwandte Themen