Как я могу динамически запрашивать ресурсы в конвейере ресурсов 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")
%>

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

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

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

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


person Irongaze.com    schedule 09.12.2011    source источник
comment
Это трудно сделать. Я попробовал несколько решений, но ни одно из них не сработало (Роб, мне пришлось удалить свой ответ. Я понял, что он «сработал» только из-за оператора //= require_tree ., который был неправильным).   -  person Marek Příhoda    schedule 10.12.2011
comment
Эй, мужик. На самом деле я нашел решение, но как новичок я не могу опубликовать его в течение следующих 4 часов. :-(   -  person Irongaze.com    schedule 10.12.2011
comment
Это довольно сложно, но в основном вы можете использовать erb для вызова require_asset вручную и использовать это в итерации цикла для выполнения необходимой работы. Рад слышать, что ваше предыдущее решение было неверным, сомневался в своем здравом уме, пытаясь воспроизвести его. Спасибо за помощь!   -  person Irongaze.com    schedule 10.12.2011


Ответы (1)


Итак, вот решение:

Внутри конвейер ресурсов (также известный как 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 в каталоге app/assets/javascripts каждого плагина.

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

person Irongaze.com    schedule 10.12.2011
comment
Но у меня с вами другой сценарий. Я хочу потребовать другую базу CSS для текущего сеанса. Но обнаружил, что в application.css.erb он понятия не имеет, что такое session. - person Rocky; 02.01.2012
comment
@Rocky - активы компилируются во время развертывания в производстве и, следовательно, не могут быть изменены на основе сеанса, файлов cookie и т. д. Лучше всего установить класс для тега ‹body› на основе сеанса (например, ‹body class=style-one› или ‹body class=style-two›) и постоянно включать оба файла css с каждый стиль имеет префикс .style-one или .style-two для сопоставления с тегом body. - person Irongaze.com; 04.01.2012
comment
Спасибо, @Irongaze.com. Это имеет смысл. - person Rocky; 04.01.2012
comment
Очень важно указать, что файл должен называться application.js.erb, иначе синтаксис неверен! - person andre.orvalho; 05.11.2014