Как я могу динамически требовать активы в конвейере Rails 3.1?

У меня есть система на основе плагинов, которую я использую для разработки приложений в Rails. Каждый плагин реализует движок с компонентами MVC и т.д. Основным приложением является просто пустая привязка, которая делегирует всю работу установленным плагинам.

В настоящее время я обновляюсь до Rails 3.1 из Rails 2.3.5 и пытаюсь подключить конвейер к моей инфраструктуре.

Проблема, с которой я сталкиваюсь, заключается в попытке программно потребовать, чтобы мои плагиновые активы были, например, в манифесте application.js.

Я могу вручную добавить их так:

//= require <plugin_manifest_path>

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

<%=
Rails.plugins.collect do |plugin|
  "//= require #{plugin}"
end.join("\n")
%>

Но я обнаружил, что фаза require/directing компиляции конвейера активов происходит до расширения ERB, поэтому сгенерированные комментарии просто заканчиваются как комментарии.

Есть ли другой механизм включения путей для компиляции, который может работать? Любой способ предварительно обработать файл манифеста до того, как обработка директивы начнется?

Если я не могу придумать ничего лучше, мне, возможно, придется написать задачу rake/deployment, которая генерирует файл манифеста plugin.js при развертывании, но мне бы хотелось, чтобы это было более ясно и элегантно. Спасибо!

EDIT. Решение найдено, опубликует полное решение, как только stackoverflow позволит мне. См. Комментарии ниже в среднем времени...

Ответ 1

ОК, так что решение:

Внутренне, конвейер активов (aka Sprockets) требует директивных вызовов context.require_asset(), чтобы фактически потребовать, чтобы какой-либо путь был указан в директиве. Оказывается, это означает, что метод require_asset присутствует и доступен во время расширения ERB. Итак, правильным решением было:

// ... Standard application.js stuff here ...
//= require_tree .
<%
Rails.plugins.each do |plugin|
  require_asset(plugin.to_s)
end
%>

Добавлено, что в, и все работало, как ожидалось. Уф!

Если вам интересно об этом значении Rails.plugins, я добавил расширение модуля Rails, чтобы получить фактический список загружаемых плагинов в порядке загрузки на основе config.plugins. Для полноты здесь:

module Rails
  def self.plugins
    # Get sorted list of all installed plugins
    all = Dir.glob(Rails.path('vendor/plugins/*/init.rb')).collect {|p| p.extract(/\/([^\/]+)\/init.rb$/) }
    all.sort!
    all.collect! {|p| p.to_sym }

    # Get our load order specification
    load_order = Rails.application.config.plugins

    # Split the load order out, and re-assemble replacing the :all keyword with the
    # set of plugins not in head or tail
    head, tail = load_order.split(:all)
    all -= head
    all -= tail

    # All set!
    head + all + tail
  end
end

И последняя деталь заключалась в создании файла манифеста <plugin_name>.js в каждом каталоге plugin app/assets/javascripts.

Надеюсь, что это поможет кому-то!