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

发布于 2024-10-17 03:04:27 字数 1224 浏览 3 评论 0原文

我正在尝试使用 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。

I'm attempting to use Jammit for packaging CSS and JS for a Rails app deployed on Heroku, which doesn't work out of the box due to Heroku's read only file system. Every example I've seen of how to do this recommends building all the packaged asset files in advance. Because of Heroku's Git-based deployment, this means you need to make a separate commit to your repository every time these files change, which is not an acceptable solution to me. Instead, I want to change the path that Jammit uses to write the cached packages to #{Rails.root}/tmp/assets (by changing ActionController::Base#page_cache_directory), which is writable on Heroku.

What I don't understand is how the cached files will be used without hitting the Rails stack every time, even using the default path for cached packages. Let me explain what I mean:

When you include a package using Jammit's helper, it looks something like this:

<%= include_javascripts :application %>

which generates this script tag:

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

When the browser requests this URL, what actually happens is that it gets routed to Jammit::Controller#package, which renders the contents of the package to the browser and then writes a cached copy to #{page_cache_directory}/assets/application.js. The idea is that this cached file is built on the first request, and subsequent requests should serve the cached file directly without hitting the Rails stack. I looked through the Jammit code and I don't see how this is supposed to happen. What prevents subsequent requests to /assets/application.js from simply routing to Jammit::Controller again and never using the cached file?

My guess is that there's a Rack middleware somewhere I'm not seeing that serves the file if it exists and forwards the request on to the controller if it doesn't. If that's the case, where is that code? And how would it work when changing ActionController::Base#page_cache_directory (effectively changing where Jammit writes cached packages)? Since #{Rails.root}/tmp is above the public document root, there's no URL that maps to that path.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

如何视而不见 2024-10-24 03:04:27

好问题!我自己没有设置这个,但这是我一直想研究的东西,所以你促使我这样做。这是我会尝试的(我很快就会自己尝试一下,但你可能会比我先一步)。

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'

Great question! I haven't set this up myself, but it's something I've been meaning to look into, so you've prompted me to do so. Here's what I would try (I'll give a shot myself soon, but you are probably going to beat me to it).

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

Now change your config.ru to:

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

Just make sure not to have anything in public/assets, since that won't ever be picked up.

Notes:

  • This is for Rails 3. Not sure of the solution under Rails 2.
  • It looks like Rack::Directory sets cache control headers to 12 hours so Heroku will cache your assets to Varnish. Not sure if Jammit sets this in its controller, but even if it doesn't, it will be cached quite quickly.
  • Heroku also sets ENV['TMPDIR'] now as well, so you can use that instead of Rails.root + '/tmp' if you wish.
独行侠 2024-10-24 03:04:27

这可能有用,它适用于不同的 gem,但想法相似,我正在尝试让它与普通的资产助手一起使用。

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

不幸的是,它似乎如果不修补/重写资产助手模块(类似于耦合的意大利面条),很难让 Rails 做到这一点。

This might be of use, it's for a different gem but the idea is similar and I'm trying to get it working with the plain asset helpers.

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

Unfortunately it seems to be quite difficult to get rails to do this without patching/rewriting the asset helpers module (which resembles coupled spaghetti).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文