Gibt es eine Rails-Funktion, um zu überprüfen, ob ein Teil vorhanden ist?

98

Wenn ich einen Teil wiedergebe, der nicht existiert, erhalte ich eine Ausnahme. Ich möchte vor dem Rendern überprüfen, ob ein Teil vorhanden ist, und falls er nicht vorhanden ist, werde ich etwas anderes rendern. Ich habe den folgenden Code in meiner .erb-Datei geschrieben, aber ich denke, es sollte einen besseren Weg geben, dies zu tun:

    <% begin %>
      <%= render :partial => "#{dynamic_partial}" %>
    <% rescue ActionView::MissingTemplate %>
      Can't show this data!
    <% end %>
Daniel Cukier
quelle
1
Die Antwort, die verwendet rescuewird , ist riskant. Ich würde mir die anderen Lösungen ansehen, bevor ich sie verwende.
Grant Hutchins

Antworten:

98

Derzeit verwende ich in meinen Rails 3 / 3.1-Projekten Folgendes:

lookup_context.find_all('posts/_form').any?

Der Vorteil gegenüber anderen Lösungen, die ich gesehen habe, ist, dass dies in allen Ansichtspfaden angezeigt wird und nicht nur in Ihrem Rails-Root. Das ist mir wichtig, da ich viele Schienenmotoren habe.

Dies funktioniert auch in Rails 4.

Zügel
quelle
9
lookup_context.exists? ('posts / find') hat bei mir nicht funktioniert. Stattdessen habe ich in diesem Beispiel lookup_context.exists? (Name, Präfix, partiell) oder lookup_content.exists? ('Find', 'posts', true) verwendet.
Jenn
2
Dies ist die aktuelle (Rails> = 3.2) Methode, um nach Vorlagen zu suchen (Quelle Apidock )
Maček
1
Befindet sich der Teil im selben Ordner wie die aktuelle Ansichtsvorlage, können Sie ihn verwenden lookup_context.exists?("find", lookup_context.prefixes, true). Auf diese Weise müssen Sie das Ansichtsverzeichnis nicht fest in den Aufruf codieren. Beachten Sie, dass dies für Teiltöne gilt. Lassen Sie für Nicht-Partials das letzte Argument weg (oder verwenden Sie false anstelle von true)
Nathan Wallace,
71

Ich hatte auch damit zu kämpfen. Dies ist die Methode, die ich letztendlich angewendet habe:

<%= render :partial => "#{dynamic_partial}" rescue nil %>

Grundsätzlich tun Sie nichts, wenn der Teil nicht existiert. Wollten Sie etwas drucken, wenn der Teil fehlt?

Edit 1: Oh, ich kann das Leseverständnis nicht verstehen. Sie haben gesagt, dass Sie etwas anderes rendern möchten. Wie wäre es in diesem Fall damit?

<%= render :partial => "#{dynamic_partial}" rescue render :partial => 'partial_that_actually_exists' %>

oder

<%= render :partial => "#{dynamic_partial}" rescue "Can't show this data!" %>

Bearbeiten 2:

Alternative: Überprüfung der Existenz der Teildatei:

<%= render :partial => "#{dynamic_partial}" if File.exists?(Rails.root.join("app", "views", params[:controller], "_#{dynamic_partial}.html.erb")) %>
Jeff
quelle
6
Meine Frage ist, dass ich keine Ausnahmen verwenden möchte, um die Flusskontrolle durchzuführen
Daniel Cukier
6
Eine Ausnahme ist eine Art Flusskontrolle, mit der Dinge behandelt werden, die über den normalen Betrieb eines Programms hinausgehen. Wenn der dynamische Teil vorhanden sein soll, aber etwas schief geht und am Ende nicht vorhanden ist, ist dies eine vernünftige Verwendung für eine Ausnahme (IMO natürlich - die ordnungsgemäße Verwendung von Ausnahmen ist selbst ein heiliger Krieg). Ich würde sagen, Ihre Alternative besteht darin, das Dateisystem zu überprüfen, ob die tatsächliche Datei vorhanden ist oder nicht. Ich werde meine Antwort mit diesem Code aktualisieren.
Jeff
3
Ich mag die Lösung, aber sie verschluckt jede Art von Ausnahme, die im Teil ausgelöst wird. IMHO macht es dies schwieriger, Fehler aufzuspüren.
Matt
5
Wenn Sie eine andere Art von Ausnahme haben, die rescue nilund ... rescue ...Methoden ausblenden. Das führt zu Fehlern, die schwer zu debuggen sind.
Nicholaides
8
Ich mag diese Lösung wirklich nicht. Rettung ist teuer und File.exists? geht davon aus, dass sich der Teil nur an einer Stelle befinden kann. Die Lösung von @ Rein unter Verwendung des lookup_context ist meiner Meinung nach der richtige Weg.
Bert Goethals
52

In einer Ansicht existiert template_exists? funktioniert, aber die aufrufende Konvention funktioniert nicht mit der einzelnen Teilnamen-Zeichenfolge, sondern erfordert template_exists? (Name, Präfix, Teil)

So überprüfen Sie den Pfad teilweise: app / views / posts / _form.html.slim

Verwenden:

lookup_context.template_exists?("form", "posts", true)
Luke Imhoff
quelle
Auf Rails 3.0.10 stellte ich fest, dass ich, wenn ich eine alternative Erweiterung wie app / views / posts / _foo.txt.erb habe, diese dem Argument wie folgt hinzufügen musste: template_exists? ("Foo.txt", "posts" , wahr)
Gabe Martin-Dempesy
Dies ist in Schienen 3.2
maček
Es scheint in Rails 3.2.x nicht delegiert zu sein, das zweite Argument ist jedoch ein Array von Präfixen. Ferner existiert es auf dem Stromregler.
Brendan
2
Sie können lookup_context.prefixes als zweites Argument verwenden: lookup_context.template_exists? ("Form", lookup_context.prefixes, true)
lion.vollnhals
Dies ist die bessere Antwort für den Zugriff auf diese Informationen über die Ansichtsebene.
Brendon Muir
30

Wenn Sie sich in Rails 3.2.13 in einem Controller befinden, können Sie Folgendes verwenden:

template_exists?("#{dynamic_partial}", _prefixes, true)

template_exists?wird delegiert an lookupcontext, wie Sie in sehen könnenAbstractController::ViewPaths

_prefixes gibt den Kontext der Vererbungskette des Controllers an.

true weil Sie nach einem Teil suchen (Sie können dieses Argument weglassen, wenn Sie eine reguläre Vorlage möchten).

http://api.rubyonrails.org/classes/ActionView/LookupContext/ViewPaths.html#method-i-template_exists-3F

Flackou
quelle
Upvoted. Aktuelle und bessere Erklärung der Parameter.
Jacobsimeon
4
Aus einer Sicht (z. B. einem Layout) funktioniert dies : lookup_context.template_exists?("navbar", controller._prefixes, :partial). Dies sagt mir, ob die aktuelle Vorlage, die dieses Layout rendert, die angegebene "Navigationsleiste" teilweise hat, und wenn ja, kann ich sie rendern. Ich gehe :partialnur, um explizit zu :partialsagen, was dieser Boolesche Wert ist - ist wahr. Danke für das _prefixesbisschen, @Flackou!
pdobb
Ersetzen Sie _prefixesdurch, nilwenn Sie einen Teil aufrufen, der sich in einem anderen übergeordneten Verzeichnis befindet.
Ben
8

Ich weiß, dass dies beantwortet wurde und eine Million Jahre alt ist, aber so habe ich es für mich behoben ...

Schienen 4.2

Zuerst habe ich dies in meine application_helper.rb eingefügt

  def render_if_exists(path_to_partial)
    render path_to_partial if lookup_context.find_all(path_to_partial,[],true).any?
  end

und jetzt anstatt anzurufen

<%= render "#{dynamic_path}" if lookup_context.find_all("#{dynamic_path}",[],true).any? %>

Ich rufe einfach an <%= render_if_exists "#{dynamic_path}" %>

hoffentlich hilft das. (habe es nicht in Rails3 versucht)

afxjzs
quelle
1
Dies funktioniert nicht, wenn Sie einen Fallback bereitstellen möchten. Lokale Variablen werden ebenfalls nicht berücksichtigt.
Phillyslick
Genau das habe ich gesucht. Sehr saubere Antwort.
Sunny
1
@BenPolinsky Ich nehme an, Sie verwenden können , def render_if_exists(*args); render(*args) if ...für diese
Websites
6

Ich habe dieses Paradigma bei vielen Gelegenheiten mit großem Erfolg verwendet:

<%=
  begin
    render partial: "#{dynamic_partial}"
  rescue ActionView::MissingTemplate
    # handle the specific case of the partial being missing
  rescue
    # handle any other exception raised while rendering the partial
  end
%>

Der Vorteil des obigen Codes besteht darin, dass wir zwei spezielle Fälle behandeln können:

  • Der Teil fehlt tatsächlich
  • Das Teil existiert, aber es hat aus irgendeinem Grund einen Fehler ausgelöst

Wenn wir nur den Code <%= render :partial => "#{dynamic_partial}" rescue nil %>oder eine Ableitung verwenden, kann der Teil existieren, aber eine Ausnahme auslösen, die stillschweigend gegessen wird und zu einer Schmerzquelle beim Debuggen wird.

br3nt
quelle
4

Was ist mit deinem eigenen Helfer:

def render_if_exists(path, *args)
  render path, *args
rescue ActionView::MissingTemplate
  nil
end
Andrey
quelle