【问题标题】:How can I dynamically require assets in the Rails 3.1 asset pipeline?如何在 Rails 3.1 资产管道中动态要求资产?
【发布时间】:2011-12-09 16:49:02
【问题描述】:

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

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

我遇到的问题是尝试以编程方式将我的插件资产要求放入 application.js 清单等。

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

//= require <plugin_manifest_path>

一切都按预期进行。但是,由于我的框架中有几十个插件,并且每次安装都有不同的组合,我希望根据安装的插件来更改清单。我尝试将此作为解决方案:

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

但我发现资产管道编译的 require/directive 阶段发生在 ERB 扩展之前,因此生成的 cmets 只是以 cmets 结尾。

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

如果我想不出更好的方法,我可能不得不编写一个 rake/deployment 任务,在部署时生成一个 plugin.js 清单文件,但如果可能的话,我希望更清晰、更优雅。谢谢!

编辑:找到解决方案,一旦 stackoverflow 允许我发布完整的解决方案。同时参见下面的 cmets...

【问题讨论】:

  • 这很难做到。我尝试了几种解决方案,但没有一个真正奏效(Rob,我不得不删除我的答案。我意识到它“有效”只是因为 //= require_tree . 声明,这是错误的)。
  • 嘿伙计。我实际上已经找到了解决方案,但作为一个新手,我无法在接下来的 4 小时内发布它。 :-(
  • 这很复杂,但基本上你可以使用 erb 手动调用require_asset,并在循环迭代中使用它来完成所需的工作。很高兴听到您之前的解决方案不正确,怀疑我试图重现它的理智。感谢您的帮助!

标签: ruby-on-rails plugins dynamic ruby-on-rails-3.1 asset-pipeline


【解决方案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

最后的细节是在每个插件的 app/assets/javascripts 目录中创建一个 &lt;plugin_name&gt;.js 清单文件。

希望对某人有所帮助!

【讨论】:

  • 但是,我对你有不同的看法。我想根据当前会话要求不同的 CSS。但是发现在application.css.erb中,不知道session是什么。
  • @Rocky - 资产是在生产中的部署时编译的,因此不能根据会话、cookie 等进行修改。您最好的选择是根据会话在 标记上设置一个类(例如 或 ),并将两个 css 文件全部包含在内时间,每个样式都以 .style-one 或 .style-two 为前缀,以匹配 body 标签。
  • 谢谢@Irongaze.com。这是有道理的。
  • 告诉文件应该被称为application.js.erb或sintax错误非常重要!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-04
  • 1970-01-01
  • 2011-11-12
  • 1970-01-01
  • 2011-11-23
  • 1970-01-01
相关资源
最近更新 更多