通过改变ActionController :: Base#page_cache_directory在Heroku上使用Jammit进行静态资产缓存

时间:2011-02-12 11:26:33

标签: ruby-on-rails heroku jammit

我正在尝试使用Jammit来打包部署在Heroku上的Rails应用程序的CSS和JS,由于Heroku的只读文件系统而无法开箱即用。我已经看到的每个如何做到这一点的例子都建议提前构建所有打包的资产文件。由于Heroku基于Git的部署,这意味着每次这些文件发生变化时都需要对存储库进行单独的提交,这对我来说是不可接受的解决方案。相反,我想更改Jammit用于将缓存的包写入#{Rails.root}/tmp/assets的路径(通过更改ActionController::Base#page_cache_directory),这可以在Heroku上写入。

我不明白的是,如果不使用Rails堆栈每次都使用缓存文件,即使使用缓存包的默认路径也是如此。让我解释一下我的意思:

当你使用Jammit的助手包含一个包时,它看起来像这样:

<%= include_javascripts :application %>

生成此脚本标记:

<script src="/assets/application.js" type="text/javascript"></script>

当浏览器请求此URL时,实际发生的是它被路由到Jammit::Controller#package,这会将包的内容呈现给浏览器,然后将缓存的副本写入#{page_cache_directory}/assets/application.js。我们的想法是,这个缓存文件是在第一个请求的基础上构建的,后续请求应直接为缓存文件提供服务,而不需要访问Rails堆栈。我查看了Jammit代码,但我看不出这是怎么发生的。是什么阻止后续请求/assets/application.js再次简单地路由到Jammit::Controller而从不使用缓存文件?

我的猜测是有一个Rack中间件,我没有看到它存在服务文件,如果它存在,并将请求转发给控制器,如果它没有。如果是这样的话,代码在哪里?如何更改ActionController::Base#page_cache_directory(有效地改变Jammit编写缓存包的位置)时它会如何工作?由于#{Rails.root}/tmp位于公共文档根目录之上,因此没有映射到该路径的URL。

2 个答案:

答案 0 :(得分:5)

好问题!我自己没有把它设置好,但这是我一直想要研究的东西,所以你促使我这样做。这是我会尝试的(我会很快给自己一个镜头,但你可能会打败我)。

config.action_controller.page_cache_directory = "#{Rails.root}/tmp/page_cache"

现在将config.ru更改为:

require ::File.expand_path('../config/environment',  __FILE__)
run Rack::URLMap.new(
   "/"       => Your::App.new,
   "/assets" => Rack::Directory.new("tmp/page_cache/assets"))

请确保public/assets中没有任何内容,因为这不会被接收。

注意:

  • 这适用于Rails 3.不确定Rails 2下的解决方案。
  • 看起来Rack::Directory将缓存控制标头设置为12小时,因此Heroku会将您的资产缓存到Varnish。不确定Jammit是否在其控制器中设置了它,但即使它没有,它也会很快缓存。
  • Heroku现在也设置了ENV['TMPDIR'],因此如果您愿意,可以使用它而不是Rails.root + '/tmp'

答案 1 :(得分:0)

这可能是有用的,它适用于不同的宝石,但这个想法很相似,我试图让它与普通的资产助手一起工作。

http://devcenter.heroku.com/articles/using-compass

不幸的是,如果没有修补/重写资产助手模块(类似于耦合的意大利面条),那么让轨道执行此操作似乎非常困难。