【问题标题】:How do you tell Rails / the asset pipeline that a js.erb depends on a YAML file?你如何告诉 Rails / 资产管道 js.erb 依赖于 YAML 文件?
【发布时间】:2013-04-30 18:34:25
【问题描述】:

我有一个从配置文件加载 YAML 的 js.erb 文件。问题是 Rails /资产管道将缓存结果并且永远不会使缓存无效,即使我更改了 YAML 文件内容。我可以重新启动 rails 服务器,甚至重新启动机器都无济于事。到目前为止,我发现的唯一解决方法是执行“rake assets:clean”。

我想找到一种方法告诉资产管道,当 YAML 文件更改时,它需要重新计算我的 js.erb。或者,或者,告诉它它只能在 rails 服务器的生命周期内缓存 js.erb / 以某种方式确保每次 rails 服务器启动或重新启动时都会重新生成。

任何建议将不胜感激。

【问题讨论】:

  • 另一种解决方法是更改 YAML 加载文件的内容(在某处添加或删除空格)。但是您的答案看起来是一个很好且完整的解决方案。

标签: ruby-on-rails asset-pipeline yaml erb


【解决方案1】:

将此添加到 config/initializers 下的文件中,它会告诉资产管道重新计算 js.erb 文件,该文件会在支持 YAML 文件之一发生更改时加载 YAML 数据:

class ConstantsPreprocessor < Sprockets::Processor
  CONSTANTS_ASSET = "support/constants"

  def evaluate(context, locals)
    if (context.logical_path == CONSTANTS_ASSET)
      Constants.load_path.each do |dir|
        dir.each do |yml|
          next unless yml.end_with?".yml"
          context.depend_on("#{dir.path}/#{yml}")
        end
      end
    end

    data
  end
end

Rails.application.assets.register_preprocessor(
    'application/javascript',
    ConstantsPreprocessor)

【讨论】:

    【解决方案2】:

    如果您使用Sprockets 3(例如,使用 Rails 5),您可以使用// depends_on。例如my-constants.js.erb:

    //= depend_on my_constants.yml
    angular
      .module('services.myConstants', [])
      .factory('myConstants', [
        function() {
          return <%= YAML::load_file(Rails.root.join('config/shared/my_constants.yml')).to_json %>;
        }
      ]);
    

    只需确保包含my_constants.yml 的目录包含在application.rb 的资产路径中即可:

    config.assets.paths.unshift Rails.root.join('config', 'shared').to_s
    

    【讨论】:

      【解决方案3】:

      我认为你有两个选择:

      1. 禁用资产管道,让 Rails 随时随地进行编译(不利于性能)

      2. 创建一个与 Rails 分离的守护进程(查找 Ruby 守护进程)以查找该特定文件中的任何更改并重新编译资产。

      3(额外!)。删除 js-YAML 依赖项并从对应用程序的 AJAX 调用中读取 YAML 的内容。场景是:JS 进行 AJAX 调用,控制器读取 YAML 文件并将其内容返回给 JS 文件。因此无需重新编译或查看 YAML 文件中的更改。

      • 如果您选择 3,请不要在控制器中读取 YAML,创建一个实用程序类来执行此操作,并让控制器要求该类读取文件并传递其内容。

      【讨论】:

      • 对于选项 1,问题在于它对性能不利,正如您所提到的。对于选项 2,重新编译所有资产将花费太长时间,或者如果您建议一种仅重新编译单个已更改资产的方法,我不明白您关于如何执行此操作的建议。选项 3 似乎很有希望,我会试一试,但似乎必须有一种更清洁的方法来做到这一点。另外,您能否提供一个更具体的示例来说明您对选项 3 的想法?
      【解决方案4】:

      您可以添加自己的处理器指令,该指令适用于assets 目录之外的文件。 = depend_on 仅适用于资产文件 (https://github.com/rails/sprockets#depend_on)

      在 config/initializers/sprockets.rb 中:

      Sprockets::DirectiveProcessor.class_eval do
        def process_depend_on_project_file_directive(file)
          path = Rails.root.join(file).to_s
          if File.exists?(path)
            deps = Set.new
            deps << @environment.build_file_digest_uri(path)
            @dependencies.merge(deps)
          end
        end
      end
      

      用法:

      //= depend_on_project_file "config/setting.yml"

      详情见github上这条评论:https://github.com/rails/sprockets/issues/500#issuecomment-491043517

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-01-31
        • 1970-01-01
        • 2012-09-12
        • 2012-05-20
        • 2012-07-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多