Есть ли в Rails функция для проверки существования партиала?

98

Когда я визуализирую несуществующий партиал, я получаю исключение. Я хотел бы проверить, существует ли партиал перед рендерингом, и если он не существует, я сделаю что-нибудь еще. Я сделал следующий код в своем файле .erb, но я думаю, что должен быть лучший способ сделать это:

    <% begin %>
      <%= render :partial => "#{dynamic_partial}" %>
    <% rescue ActionView::MissingTemplate %>
      Can't show this data!
    <% end %>
Даниэль Кукьер
источник
1
Ответ, который использует rescue, рискован. Я бы посмотрел на другие решения, прежде чем использовать его.
Грант Хатчинс,

Ответы:

98

В настоящее время я использую в своих проектах Rails 3 / 3.1 следующее:

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

Преимущество перед другими решениями, которые я видел, заключается в том, что это будет выглядеть во всех путях просмотра, а не только в корневом каталоге rails. Для меня это важно, потому что у меня много рельсовых двигателей.

Это также работает в Rails 4.

Рейн
источник
9
lookup_context.exists? ('posts / find') у меня не сработало. Вместо этого я использовал lookup_context.exists? (Имя, префикс, частично) или lookup_content.exists? ('Find', 'posts', true) в этом примере.
Дженн,
2
Это текущий (rails> = 3.2) способ проверки шаблонов (исходный код apidock )
maček
1
Если партиал находится в той же папке, что и текущий шаблон представления, вы можете использовать lookup_context.exists?("find", lookup_context.prefixes, true). Таким образом, вам не нужно жестко закодировать каталог просмотра в вызове. Обратите внимание, это для частичных файлов. Для non-partials, опустите последний аргумент (или используйте false вместо true)
Натан Уоллес,
71

Я тоже боролся с этим. В итоге я использовал этот метод:

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

В принципе, если частичное не существует, ничего не делайте. Вы хотели что-то напечатать, если часть отсутствует?

Изменить 1: О, я не понимаю прочитанного. Вы сказали, что хотите сделать что-то еще. В таком случае, как насчет этого?

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

или

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

Изменить 2:

Альтернатива: проверка существования частичного файла:

<%= render :partial => "#{dynamic_partial}" if File.exists?(Rails.root.join("app", "views", params[:controller], "_#{dynamic_partial}.html.erb")) %>
Джефф
источник
6
Мой вопрос в том, что я не хочу использовать исключения для управления потоком, что является анти-шаблоном: stackoverflow.com/questions/1546514/…
Дэниел Кукьер,
6
Исключение - это тип управления потоком, используемый для обработки вещей, которые происходят за пределами нормальной работы программы. Если предполагается, что динамический партиал присутствует, но что-то идет не так, и его там нет, то это разумное использование исключения (IMO, конечно - правильное использование исключений - это сама священная война). Я бы сказал, что ваша альтернатива - проверить файловую систему, существует ли фактический файл. Я обновлю свой ответ этим кодом.
Джефф
3
Мне нравится решение, но оно проглатывает любые исключения, возникающие в партиале. IMHO это затрудняет отслеживание ошибок.
Мэтт
5
Если у вас есть другой тип исключения, rescue nilи ... rescue ...методы будут скрывать. Это приводит к ошибкам, которые трудно отладить.
nicholaides
8
Мне это решение очень не нравится. спасение дорого, а File.exists? предполагает, что партиал может находиться только в одном месте. Я считаю, что решение @Rein с использованием lookup_context - это правильный путь.
Берт Гёталс,
52

Изнутри представления template_exists? работает, но соглашение о вызовах не работает с одной строкой частичного имени, вместо этого используется template_exists? (имя, префикс, частичное)

Чтобы проверить частичное на пути: app / views / posts / _form.html.slim

Использование:

lookup_context.template_exists?("form", "posts", true)
Люк Имхофф
источник
В Rails 3.0.10 я обнаружил, что если у меня есть альтернативное расширение, например app / views / posts / _foo.txt.erb, мне нужно добавить его к аргументу как: template_exists? ("Foo.txt", "posts" , правда)
Гейб Мартин-Демпси
Это устарело в rails 3.2
maček
Похоже, что в Rails 3.2.x он не делегирован, однако второй аргумент - это массив префиксов. Кроме того, он существует на текущем контроллере.
Брендан
2
Вы можете использовать lookup_context.prefixes в качестве второго аргумента: lookup_context.template_exists? ("Форма", lookup_context.prefixes, true)
lion.vollnhals
Это лучший ответ с точки зрения доступа к этой информации из уровня представления.
Брендон Мьюир
30

В Rails 3.2.13, если вы находитесь в контроллере, вы можете использовать это:

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

template_exists?делегировано lookupcontext, как вы можете видеть вAbstractController::ViewPaths

_prefixes дает контекст цепочки наследования контроллера.

true потому что вы ищете частичный (вы можете опустить этот аргумент, если вам нужен обычный шаблон).

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

Flackou
источник
Проголосовали. Более актуальное и лучшее объяснение параметров.
jacobsimeon
4
С точки зрения (например, расположение), это работает: lookup_context.template_exists?("navbar", controller._prefixes, :partial). Это говорит мне, имеет ли текущий шаблон, отображающий этот макет, указанную частичную «панель навигации», и если да, то я могу ее отобразить. Я прохожу мимо, :partialчтобы четко :partialуказать, что это за логическое значение - правда. Спасибо за _prefixesбит, @Flackou!
pdobb
Замените _prefixesна, nilесли вы вызываете партиал, находящийся в другом родительском каталоге.
Бен
8

Я знаю, что на это есть ответ, и ему миллион лет, но вот как я в конечном итоге исправил это для себя ...

Рельсы 4.2

Сначала я помещаю это в свой 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

и теперь вместо звонка

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

я просто звоню <%= render_if_exists "#{dynamic_path}" %>

надеюсь, это поможет. (не пробовал в rails3)

afxjzs
источник
1
Это не сработает, если вы хотите предоставить запасной вариант. Он также не принимает во внимание локальные переменные.
Phillyslick
Это именно то, что я искал. Очень чистый ответ.
Sunny
1
@BenPolinsky, я полагаю, вы можете использовать def render_if_exists(*args); render(*args) if ...для этого
сайты
6

Я много раз использовал эту парадигму с большим успехом:

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

Преимущество приведенного выше кода заключается в том, что мы можем обрабатывать отдельные случаи:

  • Частичное действительно отсутствует
  • Партиал существует, но по какой-то причине выдал ошибку

Если мы просто воспользуемся кодом <%= render :partial => "#{dynamic_partial}" rescue nil %> или какую-то производную, партиал может существовать, но вызывать исключение, которое будет незаметно съедено и станет источником боли для отладки.

br3nt
источник
4

А как насчет собственного помощника:

def render_if_exists(path, *args)
  render path, *args
rescue ActionView::MissingTemplate
  nil
end
Андрей
источник