¿Existe alguna función de Rails para comprobar si existe un parcial?

98

Cuando renderizo un parcial que no existe, obtengo una excepción. Me gustaría comprobar si existe un parcial antes de renderizarlo y, en caso de que no exista, renderizaré algo más. Hice el siguiente código en mi archivo .erb, pero creo que debería haber una mejor manera de hacer esto:

    <% begin %>
      <%= render :partial => "#{dynamic_partial}" %>
    <% rescue ActionView::MissingTemplate %>
      Can't show this data!
    <% end %>
Daniel Cukier
fuente
1
La respuesta que usa rescuees arriesgada. Vería las otras soluciones antes de usarlo.
Grant Hutchins

Respuestas:

98

Actualmente, estoy usando lo siguiente en mis proyectos Rails 3 / 3.1:

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

La ventaja sobre otras soluciones que he visto es que esto se verá en todas las rutas de vista en lugar de solo en la raíz de los rieles. Esto es importante para mí porque tengo muchos motores de raíles.

Esto también funciona en Rails 4.

Rienda
fuente
9
lookup_context.exists? ('posts / find') no funcionó para mí. En su lugar, utilicé lookup_context.exists? (Nombre, prefijo, parcial) o lookup_content.exists? ('Find', 'posts', true) en este ejemplo.
Jenn
2
Esta es la corriente (los rieles> = 3.2) forma de comprobar la fuente de plantillas ( apidock )
Maček
1
Si el parcial está en la misma carpeta que la plantilla de vista actual, puede usar lookup_context.exists?("find", lookup_context.prefixes, true). De esta manera, no necesita codificar el directorio de vista en la llamada. Tenga en cuenta que esto es para parciales. Para no parciales, omita el último argumento (o use falso en lugar de verdadero)
Nathan Wallace
71

Yo también estaba luchando con esto. Este es el método que terminé usando:

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

Básicamente, si el parcial no existe, no hagas nada. Sin embargo, ¿quería imprimir algo si faltaba el parcial?

Edición 1: Oh, fallo en la comprensión de lectura. Dijiste que querías renderizar algo más. En ese caso, ¿qué tal esto?

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

o

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

Edición 2:

Alternativa: Comprobación de la existencia del archivo parcial:

<%= render :partial => "#{dynamic_partial}" if File.exists?(Rails.root.join("app", "views", params[:controller], "_#{dynamic_partial}.html.erb")) %>
Jeff
fuente
6
Mi pregunta es que no quiero usar Excepciones para hacer el control de flujo, que es un anti-patrón: stackoverflow.com/questions/1546514/…
Daniel Cukier
6
Una excepción es un tipo de control de flujo que se usa para manejar cosas que suceden más allá del funcionamiento normal de un programa. Si se supone que el parcial dinámico está allí, pero algo sale mal y termina no estando allí, entonces ese es un uso razonable para una excepción (en mi opinión, por supuesto, el uso adecuado de las excepciones es una guerra santa en sí misma). Yo diría que su alternativa es verificar el sistema de archivos para ver si el archivo real existe o no. Actualizaré mi respuesta con ese código.
Jeff
3
Me gusta la solución, sin embargo se traga cualquier tipo de excepción lanzada en el parcial. En mi humilde opinión, esto hace que sea más difícil rastrear errores.
Matt
5
Si usted tiene un tipo diferente de excepción, las rescue nily ... rescue ...los métodos de ocultar. Eso conduce a errores que son difíciles de depurar.
nicholaides
8
Realmente no me gusta esta solución. rescatar es caro, y File.exists? asume que el parcial solo puede estar en una ubicación. La solución de @ Rein usando lookup_context es el camino a seguir, creo.
Bert Goethals
52

Desde el interior de una vista, template_exists? funciona, pero la convención de llamada no funciona con la única cadena de nombre parcial, sino que toma template_exists? (nombre, prefijo, parcial)

Para verificar si hay parcial en la ruta: app / views / posts / _form.html.slim

Utilizar:

lookup_context.template_exists?("form", "posts", true)
Luke Imhoff
fuente
En Rails 3.0.10 encontré que si tengo una extensión alternativa, como app / views / posts / _foo.txt.erb, necesitaba agregar eso al argumento como: template_exists? ("Foo.txt", "posts" , cierto)
Gabe Martin-Dempesy
Esto está obsoleto en rieles 3.2
maček
No parece estar delegado en Rails 3.2.x, sin embargo, el segundo argumento es una matriz de prefijos. Además, existe en el controlador actual.
Brendan
2
Puede usar lookup_context.prefixes como segundo argumento: lookup_context.template_exists? ("Form", lookup_context.prefixes, true)
lion.vollnhals
Esta es la mejor respuesta en términos de acceder a esta información desde la capa de vista.
Brendon Muir
30

En Rails 3.2.13, si está en un controlador, puede usar esto:

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

template_exists?se delega a lookupcontext, como puede ver enAbstractController::ViewPaths

_prefixes da el contexto de la cadena de herencia del controlador.

true porque está buscando un parcial (puede omitir este argumento si desea una plantilla normal).

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

Flackou
fuente
Voto a favor. Más actualizado y mejor explicación de los parámetros.
jacobsime el
4
Desde un punto de vista (por ejemplo, un diseño), funciona esto: lookup_context.template_exists?("navbar", controller._prefixes, :partial). Esto me dice si la plantilla actual que representa este diseño tiene la "barra de navegación" parcial, y si es así puedo renderizarla. Paso :partialsolo para ser explícito sobre qué es ese booleano: :partiales verdad. ¡Gracias por el _prefixespoco, @Flackou!
pdobb
Reemplácelo _prefixescon nilsi está llamando a un parcial que se encuentra en un directorio principal diferente.
ben
8

Sé que esto ha sido respondido y tiene un millón de años, pero así es como terminé arreglándome esto ...

Carriles 4.2

Primero, puse esto en mi 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

y ahora en lugar de llamar

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

Acabo de llamar <%= render_if_exists "#{dynamic_path}" %>

Espero que ayude. (no lo he probado en rails3)

afxjzs
fuente
1
Esto no funciona si desea proporcionar una alternativa. Tampoco toma en consideración las variables locales.
phillyslick
Esto es exactamente lo que estaba buscando. Respuesta muy limpia.
Soleado
1
@BenPolinsky supongo que se puede utilizar def render_if_exists(*args); render(*args) if ...para que
los sitios
6

He utilizado este paradigma en muchas ocasiones con gran éxito:

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

El beneficio del código anterior es que podemos manejar casos específicos de remolque:

  • De hecho, falta el parcial
  • El parcial existe, pero arrojó un error por alguna razón

Si solo usamos el código <%= render :partial => "#{dynamic_partial}" rescue nil %>o algún derivado, el parcial puede existir pero generar una excepción que será devorada silenciosamente y se convertirá en una fuente de dolor para depurar.

br3nt
fuente
4

¿Y tu propio ayudante?

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