{"id":234,"date":"2009-07-08T17:30:16","date_gmt":"2009-07-08T15:30:16","guid":{"rendered":"http:\/\/hjacob.com\/blog\/?p=234"},"modified":"2009-07-19T23:50:41","modified_gmt":"2009-07-19T21:50:41","slug":"404-und-500-fehler-in-rails-richtig-bearbeiten","status":"publish","type":"post","link":"https:\/\/hjacob.com\/blog\/404-und-500-fehler-in-rails-richtig-bearbeiten\/","title":{"rendered":"404 und 500 Fehler in Rails richtig bearbeiten"},"content":{"rendered":"<p>Die Fehlerausgabe in Ruby on Rails kann manchmal zur Verzweiflung f\u00fchren. Zwar gibt es von Haus aus die beiden Fehlerdateien &#8222;404.html&#8220; und &#8222;500.html&#8220; im public Ordner &#8211; was aber tuen, wenn man diese Seiten nicht statisch ausliefern will und stattdessen eine dynamische Fehlerseite generieren m\u00f6chte.<\/p>\n<p><!--more Rails Code f\u00fcr dynamische Fehlerbehandlung zeigen --><\/p>\n<h2>1. Schritt: Fehlermeldung dynamisch generieren<\/h2>\n<p>Seit Rails 2.0 gibt es die praktische Methode <b>rescue_action_in_public()<\/b>. Diese wird automatisch aufgerufen, wenn beim Rendern der Seite etwas schiefgeht. Dabei ist zu beachten, dass rescue_action_in_public nicht aufgerufen wird, wenn der Request local war. Also nicht wundern, wenn auf dem heimischen Testserver weiterhin die Error Logs angezeigt werden (ist ja auch besser so f\u00fcrs Debugging).<\/p>\n<p>Eine praktische Anwendung f\u00fcr rescue_action_in_public w\u00e4re die folgende (eingef\u00fcgt in die <b>controller\/application.rb<\/b> damit es global gilt):<\/p>\n<p>[sourcecode lang=&#8220;ror&#8220;]<br \/>\n  def rescue_action_in_public(exception)<br \/>\n    set_meta(&quot;robots&quot;,&quot;noindex&quot;)<br \/>\n    case exception<br \/>\n       when ::ActiveRecord::RecordNotFound<br \/>\n       when ::ActiveRecord::RecordInvalid<br \/>\n       when ::ActionController::RoutingError<br \/>\n       when ::ActionController::UnknownController<br \/>\n       when ::ActionController::UnknownAction<br \/>\n       when ::ActionController::MethodNotAllowed<br \/>\n         render :template =&gt; &quot;\/general\/error_404.html.erb&quot;, :status =&gt; 404<br \/>\n       else<br \/>\n         render :template =&gt; &quot;\/general\/error_500.html.erb&quot;, :status =&gt; 500<br \/>\n     end<br \/>\n  end<br \/>\n[\/sourcecode]<\/p>\n<p>Der Code ist ja ziemlich selbstsprechend, wenn ein Fehler auftritt, bei dem etwas fehlt (Datenbankeintrag, Action, Methode, etc.) wird ein 404 Fehler ausgegeben (dabei wird hier die Datei &#8222;\/general\/error_404.html.erb&#8220; gerendert). Ansonsten die entsprechende 500er Fehlerdatei. Alternativ k\u00f6nnte man nat\u00fcrlich auch einen Redirect auf eine beliebige Seite einbauen.<\/p>\n<p>Noch zu bemerken sei der Befehl <b>set_meta(&#8222;robots&#8220;,&#8220;noindex&#8220;)<\/b> &#8211; hier rufe ich die (selbstgeschriebene) Methode zum Setzen des Meta Datensatzes &#8222;Robots&#8220; auf und gebe dort an, dass die fehlerhafte Seite nicht indiziert werden soll. Damit die Seite nicht trotz eines 404 Status-Codes in einem Suchmaschinenindex landet. <\/p>\n<h2>2. Schritt: Statische Dateien l\u00f6schen<\/h2>\n<p>Der Ordnung zu liebe sollte man nun noch die Dateien 404.html und 500.html im <b>public<\/b> Folder l\u00f6schen oder zumindest umbenennen, so dass der Webserver diese nicht mehr direkt ausliefert, wenn die URL &#8222;http:\/\/www.meine-url.de\/404.html&#8220; ge\u00f6ffnet wird, sei es durch einen Redirect oder sonst wie.<\/p>\n<p>Danach noch die <b>routes.rb<\/b> im &#8222;\/config&#8220; Ordner um die folgenden Zeilen erg\u00e4nzen (ganz am Ende einf\u00fcgen!):<\/p>\n<p>[sourcecode lang=&#8220;ror&#8220;]<br \/>\n  map.connect &#8218;\/404.:format&#8216;, :controller =&gt; &quot;\/general&quot;, :action =&gt; &quot;error_404&quot;<br \/>\n  map.connect &#8218;\/404&#8216;, :controller =&gt; &quot;\/general&quot;, :action =&gt; &quot;error_404&quot;<br \/>\n  map.connect &#8218;\/500.:format&#8216;, :controller =&gt; &quot;\/general&quot;, :action =&gt; &quot;error_500&quot;<br \/>\n  map.connect &#8218;\/500&#8216;, :controller =&gt; &quot;\/general&quot;, :action =&gt; &quot;error_500&quot;<br \/>\n  map.connect &#8218;*path&#8216;, :controller =&gt; &#8218;\/general&#8216;, :action =&gt; &#8218;error_404&#8216; unless ::ActionController::Base.consider_all_requests_local<br \/>\n[\/sourcecode]<\/p>\n<p>Hier werden dann die Direktaufrufe der 404.html und \/404 auf das richtige Script umgeleitet. Die letzte Zeile wiederum greift, wenn die aufgerufene URL zu gar keiner anderen Route passt, dann wird ebenfalls die 404 Fehlermeldung gerendert. Letzteres k\u00f6nnte man auch weglassen, denn wenn diese Route nicht da w\u00e4re, w\u00fcrde eh ein <i>ActionController::UnknownAction<\/i> Fehler eintreten und dann greift ja wieder die rescue_action_in_public().<\/p>\n<h2>Design Patterns<\/h2>\n<p>Nat\u00fcrlich kann man in jeden einzelnen Controller eine eigene <b>rescue_action_in_public<\/b> Methode einbauen, um so die Fehlerseite m\u00f6glichst auf den Context anzupassen. So w\u00fcrde es zum Beispiel Sinn machen, in einen Mp3 Controller eine Fehlerseite einzubauen, die den Benutzer informiert, dass das gew\u00fcnschte Mp3 File nicht vorhanden ist, er sich doch aber die folgenden anderen Songs anh\u00f6ren k\u00f6nnte. Auf diese Weise h\u00e4lt man sich an moderne Designrichtlinien, die genau dies empfehlen: Den Besucher nicht auf einer langweiligen 404-Fehlerseite zur\u00fccklassen, sondern stattdessen ihn an die Hand zu nehmen und zu g\u00fcltigen Inhalten zu f\u00fchren.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wie man 404 und 500 Fehlerseiten in Ruby on Rails mit Hilfe der rescue_action_in_public Methode in eine dynamische Fehlerseite verwandelt und so Besucher auf der Seite behalten kann.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[84,3],"tags":[89,88,86,85,87],"_links":{"self":[{"href":"https:\/\/hjacob.com\/blog\/wp-json\/wp\/v2\/posts\/234"}],"collection":[{"href":"https:\/\/hjacob.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hjacob.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hjacob.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/hjacob.com\/blog\/wp-json\/wp\/v2\/comments?post=234"}],"version-history":[{"count":8,"href":"https:\/\/hjacob.com\/blog\/wp-json\/wp\/v2\/posts\/234\/revisions"}],"predecessor-version":[{"id":238,"href":"https:\/\/hjacob.com\/blog\/wp-json\/wp\/v2\/posts\/234\/revisions\/238"}],"wp:attachment":[{"href":"https:\/\/hjacob.com\/blog\/wp-json\/wp\/v2\/media?parent=234"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hjacob.com\/blog\/wp-json\/wp\/v2\/categories?post=234"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hjacob.com\/blog\/wp-json\/wp\/v2\/tags?post=234"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}