如何在Rails 3.1资产管道中动态需要资产?

Iro*_*com 11 plugins ruby-on-rails dynamic ruby-on-rails-3.1 asset-pipeline

我有一个基于插件的系统,我用它在Rails中进行应用程序开发.每个插件都实现了一个带有MVC组件等的引擎.主应用程序只是一个空的线束,它将所​​有工作委托给安装的插件.

我目前正在从Rails 2.3.5升级到Rails 3.1,并试图让资产管道与我的框架一起工作.

我遇到的问题是尝试以编程方式要求我的插件的资源,例如,application.js清单.

我可以像这样手动添加它们:

//= require <plugin_manifest_path>
Run Code Online (Sandbox Code Playgroud)

一切都按预期工作.但是,由于我的框架中有许多插件,并且每个安装都有不同的组合,我希望根据安装的插件进行此清单更改.我试过这个解决方案:

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

但我发现资产管道编译的require/directive阶段发生在ERB扩展之前,因此生成的注释最终只是注释.

是否有另一种机制可以包含可能有效的编译路径?在指令处理开始之前预先处理清单文件的任何方法?

如果我想不出更好的东西,我可能必须编写一个rake/deployment任务,在部署时生成一个plugin.js清单文件,但如果可能的话,我会喜欢更清晰,更优雅的东西.谢谢!

编辑:发现解决方案,一旦stackoverflow让我发布完整的解决方案.同时查看以下评论​​......

Iro*_*com 13

好的,所以这是解决方案:

在内部,资产管道(又称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
%>
Run Code Online (Sandbox Code Playgroud)

添加了,并且所有工作都按预期工作.呼!

如果你想知道那个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
Run Code Online (Sandbox Code Playgroud)

最后的细节是<plugin_name>.js在每个插件的app/assets/javascripts目录中创建一个清单文件.

希望有人帮助!