Esiste una funzione Rails per verificare se esiste un parziale?


98

Quando eseguo il rendering di un partial che non esiste, ottengo un'eccezione. Vorrei controllare se esiste un parziale prima di renderlo e nel caso non esista, renderò qualcos'altro. Ho eseguito il codice seguente nel mio file .erb, ma penso che dovrebbe esserci un modo migliore per farlo:

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

1
La risposta che usa rescueè rischiosa. Guarderei le altre soluzioni prima di usarlo.
Grant Hutchins

Risposte:


98

Attualmente, sto usando quanto segue nei miei progetti Rails 3 / 3.1:

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

Il vantaggio rispetto ad altre soluzioni che ho visto è che questo cercherà in tutti i percorsi di visualizzazione invece che solo nella radice dei binari. Questo è importante per me perché ho molti motori ferroviari.

Funziona anche in Rails 4.


9
lookup_context.exists? ('posts / find') non ha funzionato per me. In questo esempio ho usato lookup_context.exists? (Name, prefix, partial) o lookup_content.exists? ('Find', 'posts', true).
Jenn il

2
Questo è il modo corrente (rails> = 3.2) per controllare i modelli (fonte apidock )
maček

1
Se il parziale si trova nella stessa cartella del modello di visualizzazione corrente, è possibile utilizzare lookup_context.exists?("find", lookup_context.prefixes, true). In questo modo, non è necessario codificare la directory della vista nella chiamata. Nota, questo è per i parziali. Per non parziali, ometti l'ultimo arg (o usa false invece di true)
Nathan Wallace,

71

Stavo lottando anche con questo. Questo è il metodo che ho finito per usare:

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

Fondamentalmente, se il parziale non esiste, non fare nulla. Volevi stampare qualcosa se manca il parziale?

Modifica 1: Oh, non riesco a comprendere la lettura. Hai detto che volevi renderizzare qualcos'altro. In tal caso, che ne dici di questo?

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

o

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

Modifica 2:

Alternativa: verifica dell'esistenza del file parziale:

<%= render :partial => "#{dynamic_partial}" if File.exists?(Rails.root.join("app", "views", params[:controller], "_#{dynamic_partial}.html.erb")) %>

6
La mia domanda è che non voglio usare le eccezioni per eseguire il controllo del flusso, che è un anti-pattern: stackoverflow.com/questions/1546514/…
Daniel Cukier

6
Un'eccezione è un tipo di controllo di flusso utilizzato per gestire cose che accadono oltre il normale funzionamento di un programma. Se il parziale dinamico dovrebbe essere lì ma qualcosa va storto e finisce per non esserci, allora è un uso ragionevole per un'eccezione (IMO, ovviamente - l'uso corretto delle eccezioni è una guerra santa stessa). Direi che la tua alternativa è controllare il filesystem per verificare se il file reale esiste o meno. Aggiornerò la mia risposta con quel codice.
Jeff

3
La soluzione mi piace, tuttavia ingoia ogni tipo di eccezione lanciata nel parziale. IMHO questo rende più difficile rintracciare gli errori.
Matt

5
Se si dispone di un diverso tipo di eccezione, i metodi rescue nile ... rescue ...lo nascondono. Ciò porta a bug difficili da eseguire il debug.
nicholaides

8
Non mi piace davvero questa soluzione. il salvataggio è costoso e File.exists? presume che il parziale possa trovarsi solo in una posizione. La soluzione di @ Rein utilizzando il lookup_context è la strada da percorrere credo.
Bert Goethals

52

Dall'interno di una vista, template_exists? funziona, ma la convenzione di chiamata non funziona con la singola stringa del nome parziale, invece accetta template_exists? (nome, prefisso, parziale)

Per controllare il percorso parziale: app / views / posts / _form.html.slim

Uso:

lookup_context.template_exists?("form", "posts", true)

Su Rails 3.0.10 ho scoperto che se ho un'estensione alternativa, come app / views / posts / _foo.txt.erb, dovevo aggiungerla all'argomento come: template_exists? ("Foo.txt", "posts" , vero)
Gabe Martin-Dempesy

Questo è deprecato in rails 3.2
maček

Non sembra essere delegato in Rails 3.2.x, tuttavia, il secondo argomento è un array di prefissi. Inoltre, esiste sul controller corrente.
Brendan

2
Puoi utilizzare lookup_context.prefixes come secondo argomento: lookup_context.template_exists? ("Form", lookup_context.prefixes, true)
lion.vollnhals

Questa è la risposta migliore in termini di accesso a queste informazioni dal livello di visualizzazione.
Brendon Muir

30

In Rails 3.2.13, se sei in un controller, puoi usare questo:

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

template_exists?è delegato a lookupcontext, come puoi vedere inAbstractController::ViewPaths

_prefixes fornisce il contesto della catena di ereditarietà del controller.

true perché stai cercando un parziale (puoi omettere questo argomento se vuoi un modello regolare).

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


Votato. Spiegazione dei parametri più aggiornata e migliore.
jacobsimeon

4
Dal punto di vista (ad esempio un layout), questo funziona: lookup_context.template_exists?("navbar", controller._prefixes, :partial). Questo mi dice se il modello corrente che rende questo layout ha la parziale "barra di navigazione" dichiarata, e se è così posso renderlo. Passo :partialsolo per essere esplicito su cosa sia quel booleano - :partialè vero. Grazie per il _prefixesbit, @Flackou!
pdobb

Sostituisci _prefixescon nilse stai chiamando un partial che si trova in una directory padre diversa.
ben

8

So che ha avuto una risposta ed è vecchia di un milione di anni, ma ecco come ho finito per risolverlo per me ...

Rotaie 4.2

Per prima cosa, lo metto nel mio application_helper.rb

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

e ora invece di chiamare

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

chiamo e basta <%= render_if_exists "#{dynamic_path}" %>

spero che aiuti. (non ho provato in rails3)


1
Questo non funziona se vuoi fornire un fallback. Inoltre non prende in considerazione le variabili locali.
phillyslick

Questo e 'esattamente quello che stavo cercando. Risposta molto pulita.
Soleggiato

1
@BenPolinsky Suppongo che tu possa usare def render_if_exists(*args); render(*args) if ...per quello
siti

6

Ho utilizzato questo paradigma in molte occasioni con grande successo:

<%=
  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
%>

Il vantaggio del codice sopra è che possiamo gestire casi specifici di rimorchio:

  • Il parziale è infatti mancante
  • Il parziale esiste, ma per qualche motivo ha generato un errore

Se usiamo solo il codice <%= render :partial => "#{dynamic_partial}" rescue nil %>o qualche derivato, il parziale può esistere ma solleva un'eccezione che verrà mangiata silenziosamente e diventerà una fonte di dolore per il debug.


4

E il tuo aiutante:

def render_if_exists(path, *args)
  render path, *args
rescue ActionView::MissingTemplate
  nil
end
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.