2013-04-04 6 views
7

Ich bin auf der Suche nach einer Fehlermeldung in einer Jbuilder-Ansicht. Zum Beispiel könnte haben könnte ein Weg ich:Rails richtige Möglichkeit, Fehler mit Jbuilder anzuzeigen

/foos/:id/bars

Wenn :id vom Benutzer eingereicht nicht vorhanden oder ungültig ist, würde ich die Fehlermeldung zu können, wie entsprechend in meiner index.json.builder Datei anzuzeigen .

Mit Rails, was ist der beste Weg, um dies zu tun? Die Steuerung könnte etwas haben, wie:

def index 
    @bar = Bar.where(:foo_id => params[:id]) 
end 

In diesem Fall params[:id] sein könnte nil, oder das Objekt möglicherweise nicht vorhanden. Ich bin mir nicht sicher, ob das Beste, was hier zu tun ist, ist es in der Steuerung zu behandeln und explizit eine error.json.builder rendern, oder behandeln Sie es in der Ansicht selbst. Was ist der richtige Weg, dies zu tun, und wenn es in der index.json.builder ist, ist params[:id] verfügbar, um dort zu überprüfen? Ich weiß, ich kann sehen, ob @bar.nil? aber nicht sicher auf die Umkehrung?

Antwort

4

Ich würde index.json.builder machen oder einfach nur Inline-json mit :error => 'not found' Und vergessen Sie nicht die richtigen HTTP-Status zu setzen: :status => 404

So wie folgt aussehen führen könnte:

render :json => { :error => 'not found' }, :status => 422 if @bar.nil? 
4

I Ich denke, du meintest Show, denn der Index ist wirklich für Listen/Sammlungen. Und Sie sollten .first auf dem wo, sonst haben Sie nur eine Beziehung, richtig? Verwenden Sie dann .first!, um einen Fehler zu beheben, da Rails Rack-Middleware in Rails 4 public_exceptions behandelt wird, ist in einer grundlegenden Art und Weise, z.

def show 
    # need to do to_s on params value if affected by security issue CVE-2013-1854 
    @bar = Bar.where(:foo_id => params[:id].to_s).first! 
end 

Sie können auch @bar = Bar.find(params[:id]), verwenden aber das ist veraltet und wird in Rails 4.1 entfernt werden, wonach Sie gem 'activerecord-deprecated_finders' zu Ihrem Gemfile hätte hinzufügen zu verwenden.

Für den Index möchten Sie wahrscheinlich @bars = Bar.all. Wenn Sie aus irgendeinem Grund filtern wollen und nicht wollen, etc., dann könnten Sie @bars = Bar.where(...).to_a oder ähnliches verwenden.

Rails 4: Grund Exception Handling in Rack ist Automatische

Solange die Abfrage einen Fehler weg tritt, werden die Nachricht Teil des Fehlers für jedes unterstützte Format where to_(format) können Rails 4 in der Lage sein sollte, zurückzukehren aufgerufen ein Hash (zB json, xml, etc.).

Um zu sehen, warum, werfen Sie einen Blick auf Rails Rack public_exceptions Middleware.

Wenn es HTML ist, wird es versuchen, in die entsprechende Datei aus dem öffentlichen Verzeichnis in Rails für den Statuscode einzulesen (z. B. 500.html für einen Serverfehler/HTTP 500).

Wenn es ein anderes Format ist, wird es to_(the format) auf dem Hash versuchen: { :status => status, :error => exception.message }.Um zu sehen, wie dies funktioniert zu Rails gehen würde Konsole:

$ rails c 
... 
1.9.3p392 :001 > {status: 500, error: "herro shraggy!"}.to_xml 
=> "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<hash>\n <status type=\"integer\">500</status>\n <error>herro shraggy!</error>\n</hash>\n" 
1.9.3p392 :002 > {status: 500, error: "herro shraggy!"}.to_json 
=> "{\"status\":500,\"error\":\"herro shraggy!\"}" 

In der Middleware, werden Sie die X-Cascade Header im Code und an verschiedenen Orten sehen im Zusammenhang mit Rails' Ausnahmebehandlung in der Zahnstange. Pro this answer wird die X-Cascade-Kopfzeile auf pass gesetzt, um Rack mitzuteilen, dass es andere Routen versuchen soll, um eine Ressource zu finden.

Rails 3.2.x: Kann Griff Ausnahmen in Rack-

In Rails 3.2.x, dass Code to_(format) für die Antwort Körper zu tun, usw. ist nicht in public_exceptions.rb. Es handhabt nur HTML-Format.

Vielleicht könnten Sie versuchen, die alte Middleware mit der neueren Version durch einen Patch zu ersetzen.

Wenn Sie möchten, dass Rack Ihren Fehler auf eine spezifischere Weise behandelt, ohne einen Patch, siehe # 3 in José Valims Beitrag, "My five favorite “hidden” features in Rails 3.2".

In diesem und als another answer erwähnt, können Sie config.exceptions_app = self.routes verwenden. Mit Routen, die auf einen benutzerdefinierten Controller verweisen, können Sie die Fehler von jedem Controller wie jede andere Anfrage behandeln. Beachten Sie das Bit über config.consider_all_requests_local = false in Ihrem config/environments/development.rb.

Sie müssen keine Routen verwenden, um exceptions_app zu verwenden. Obwohl es ein wenig einschüchternd sein kann, ist es nur ein proc/lambda, das einen Hash nimmt und ein Array zurückgibt, dessen Format ist: [http_status_code_number, {headers hash...}, ['the response body']]. Zum Beispiel sollten Sie in der Lage sein, diese Konfiguration in Ihrer Rails 3.2.x zu tun, um es Fehler wie Rails 4.0 behandeln zu lassen (dies ist die neueste public_exceptions Middleware kollabierte):

config.exceptions_app = lambda do |env| 
    exception = env["action_dispatch.exception"] 
    status = env["PATH_INFO"][1..-1] 
    request = ActionDispatch::Request.new(env) 
    content_type = request.formats.first 
    body = { :status => status, :error => exception.message } 
    format = content_type && "to_#{content_type.to_sym}" 
    if format && body.respond_to?(format) 
    formatted_body = body.public_send(format) 
    [status, {'Content-Type' => "#{content_type}; charset=#{ActionDispatch::Response.default_charset}", 
      'Content-Length' => body.bytesize.to_s}, [formatted_body]] 
    else 
    found = false 
    path = "#{public_path}/#{status}.#{I18n.locale}.html" if I18n.locale 
    path = "#{public_path}/#{status}.html" unless path && (found = File.exist?(path)) 

    if found || File.exist?(path) 
     [status, {'Content-Type' => "text/html; charset=#{ActionDispatch::Response.default_charset}", 
       'Content-Length' => body.bytesize.to_s}, [File.read(path)]] 
    else 
     [404, { "X-Cascade" => "pass" }, []] 
    end 
    end 
end 

Hinweis: Für jedes Problem mit dieser Handhabung , die fehlersichere Implementierung ist in ActionDispatch::ShowExceptionshere.

Rails 3 und 4:

Wenn Sie eher Fehler Rendering in der Steuerung selbst haben möchten, können Sie tun einige Ausnahmen in Rails-Controller Handhabung:

def show 
    respond_with @bar = Bar.where(:foo_id => params[:id].to_s).first! 
rescue ActiveRecord::RecordNotFound => e 
    respond_to do |format| 
    format.json => { :error => e.message }, :status => 404 
    end 
end 

Aber Sie brauchen nicht um Fehler zu melden. Sie könnten auch tun:

def show 
    @bar = Bar.where(:foo_id => params[:id].to_s).first 
    if @bar 
    respond_with @bar 
    else 
    respond_to do |format| 
     format.json => { :error => "Couldn't find Bar with id=#{params[:id]}" }, :status => 404 
    end 
    end 
end 

Sie auch rescue_from verwenden können, beispielsweise in Ihrem Controller oder Application, etc .:

rescue_from ActiveRecord::RecordNotFound, with: :not_found 

def not_found(exception) 
    respond_to do |format| 
    format.json => { :error => e.message }, :status => 404 
    end 
end 

oder:

rescue_from ActiveRecord::RecordNotFound do |exception| 
    respond_to do |format| 
    format.json => { :error => e.message }, :status => 404 
    end 
end 

Obwohl einige häufige Fehler in der Steuerung verarbeitet werden kann, wenn Sie Fehler fehlende Routen im Zusammenhang usw. in json formatiert usw. müssen diese in Rack-Middleware behandelt werden.

Verwandte Themen