2012-11-17 1 views
14

Ich bin über eine Situation gestolpert, wo meine Anwendung nach einer ID sucht, die nicht in der Datenbank existiert. Eine Ausnahme wird ausgelöst. Natürlich ist dies eine Standard-Situation für jeden Webentwickler.Allgemeine Rettung im gesamten Controller, wenn ID nicht gefunden wurde - RoR

Dank this answer Ich weiß, dass ziemlich ordentlich Rettung beschäftigt sich mit der Situation mit, etwa so:

def show 
    @customer = Customer.find(params[:id]) 
    rescue ActiveRecord::RecordNotFound #customer with that id cannot be found 
    redirect_to action: :index  #redirect to index page takes place instead of crashing 
end 

Falls der Kunde nicht gefunden werden kann, kann der Benutzer auf der Index-Seite umgeleitet wird. Das funktioniert absolut gut.

Jetzt ist das alles nett, aber ich muss die gleichen Rettungsversuche in Aktionen wie zeigen, bearbeiten, zerstören, usw., d. H. jede Controller-Methode, die eine bestimmte ID benötigt.

Having said that, hier meine Frage ist: Gibt es keine Möglichkeit, im Allgemeinen, dass mein Controller zu sagen, wenn es nicht die ID in einen seiner Methoden finden, um es in der Index-Seite umleiten soll (oder im Allgemeinen, führen Sie eine bestimmte Aufgabe aus)? eine eingebaute in rescue_from Klassenmethode

Antwort

31

Sie rescue_from für diese Aufgabe verwenden müssen. Siehe Beispiel in den Action Controller Overview Guide

class ApplicationController < ActionController::Base 
    rescue_from ActiveRecord::RecordNotFound, :with => :record_not_found 

    private 

    def record_not_found 
    redirect_to action: :index 
    end 
end 
+1

Super, das macht den Trick, danke! Aus Neugier: Warum sollte diese Methode privat sein? – weltschmerz

+1

Nur für Sauberkeit: die Methode muss nicht für andere Controller sichtbar sein, deshalb wird sie als privat deklariert. Es würde gleichermaßen funktionieren, wenn die Methode nicht als privat deklariert wird. – Baldrick

+2

Sie könnten auch eine Flash-Nachricht hinzufügen flash [: notice] = "No record found" –

8

Rails hat:

class CustomersController < ApplicationController 
    rescue_from ActiveRecord::RecordNotFound, with: :index 
    ... 
end 
+0

Das sieht sehr elegant aus. Ich habe es versucht, aber es lässt mich mit einer leeren Seite im Browser, und in der URL sagt es noch immer "customers /: id". Fehle ich etwas? Es scheint mir, es versucht Index zu machen, anstatt darauf umzuleiten. – weltschmerz

+0

Sie haben Recht .. versuchen Sie etwas wie das, was Baldrick unten empfiehlt (d. H. Eine Zwischenmethode mit einer Weiterleitung). –

1

In bestimmten Fällen, würde ich empfehlen, dass Sie Model.find_by_id(id) verwenden zu Model.find(id) gegenüber. Statt eine Ausnahme auszulösen, gibt .find_by_idnil zurück. wenn der Datensatz nicht gefunden werden konnte.

Achten Sie nur darauf, nach Nils zu suchen, um zu vermeiden, NoMethodError!

P.S. Für das, was es wert ist, ist Model.find_by_id(id) funktionell gleichwertig zu Model.where(id: id), die Ihnen erlauben würde, einige zusätzliche Beziehungen aufzubauen, wenn Sie möchten. dann sind hier ein paar Optionen

3

Wenn Sie über das tun dies in einem einzigen Controller zu sprechen (wie in jedem Controller zu tun dies global gegen):

Sie eine before_filter einrichten Ihre Ressource verwenden können:

class CustomerController < ApplicationController 
    before_filter :get_customer, :only => [ :show, :update, :delete ] 

    def show 
    end 

    private 

    def get_customer 
    @customer = ActiveRecord.find(params[:id]) 
    rescue ActiveRecord::RecordNotFound 
     redirect_to :action => :index 
    end 
end 

Oder Sie können stattdessen eine Methode verwenden. Ich habe in diese Richtung bewegt, anstatt Instanzvariablen in Ansichten zu verwenden, und es würde Ihnen auch helfen, Ihr Problem zu lösen:

class CustomerController < ApplicationController 
    def show 
    # Uses customer instead of @customer 
    end 

    private 

    def customer 
    @customer ||= Customer.find(params[:id]) 
    rescue ActiveRecord::RecordNotFound 
     redirect_to :action => :index 
    end 
    helper_method :customer 
end 
+0

Das Wort "global" hat meine Aufmerksamkeit erregt. Gibt es eine Möglichkeit, dies bei allen Controllern zu tun? Das wäre sehr hilfreich. – weltschmerz

+1

Ich denke, zu tun, was ich global beschrieben habe, könnte ein wenig Metaprogrammierung erfordern. Aber um ActiveRecord :: RecordNotFound global zu retten, könnten Sie rescue_from in Ihrem ApplicationController verwenden. – bratsche

Verwandte Themen