6

We're using Rails asset caching for JS and CSS like this:

<%= stylesheet_link_tag 'reset','global','admins','autocomplete', 'date_input', 'tablesorter', 'partners', 'jqmodal', :media => 'screen', :cache => set_asset_cache(:admins) %>
<%= javascript_include_tag :defaults, 'autocomplete', 'searchbox', 'jqmodal', :cache => set_asset_cache(:admins) %>

In our deploy we call rake tmp:assets:clear each time. The problem is that the first few page loads after a deploy come up with no css or js on the page. I guess until the cached all.js and all.css have been regenerated.

We deploy many times per day and this is scary for any users who happen to come across a busted page.

Have people found any way to make this smoother so the new cached assets are guaranteed to be there on the first new page load?

Brian Armstrong
  • 19,707
  • 17
  • 115
  • 144
  • A few questions: 1) Do you have multiple app servers on different machines? 2) What is the cache line for the CSS in the templates? – scottd May 11 '10 at 14:24
  • Hi Scott. All app servers on one machine. Here is an example of the css cache line: `<%= stylesheet_link_tag 'reset','global','admins','autocomplete', 'date_input', 'tablesorter', 'partners', 'jqmodal', :media => 'screen', :cache => set_asset_cache(:admins) %>` We have separate ones for admins, buyers, sellers, landing pages, etc (one per layout). Thanks! – Brian Armstrong May 11 '10 at 19:51

2 Answers2

3

The AssetHat gem addresses this exact problem. Instead of concatenating assets the first time a page is loaded (which increases that page's load time), it concatenates assets on deploy instead. As a bonus, the gem also minifies your CSS and JS, which saves precious bytes.

After setup, usage is pretty simple:

  • Use include_css :bundle => 'admins' and include_js :bundle => 'admins' in your layout. (The bundle contents are set in a config file to keep your layout lightweight.)
  • Add rake asset_hat:minify to your deploy script. My company has been using it in production with Capistrano for about a year now.

There's more info in the readme and docs, and I'd be happy to hear any questions/ideas!

Ron DeVera
  • 14,394
  • 6
  • 41
  • 36
1

You could try warming the cache during deployment using wget, as an example (shamelessly reposted):

wget -r -nd --delete-after http://whatever.com/~popular/page/

However, this would have to be executed after you switch your symlink to your new deployment. A possibly more elegant solution might be to call the asset caching methods manually in your deploy, though I'm not sure how feasible that is. Here's where the caching is performed in Rails:

# File vendor/rails/actionpack/lib/action_view/helpers/asset_tag_helper.rb, line       273
273:       def javascript_include_tag(*sources)
274:         options = sources.extract_options!.stringify_keys
275:         concat  = options.delete("concat")
276:         cache   = concat || options.delete("cache")
277:         recursive = options.delete("recursive")
278: 
279:         if concat || (ActionController::Base.perform_caching && cache)
280:           joined_javascript_name = (cache == true ? "all" : cache) + ".js"
281:           joined_javascript_path = File.join(joined_javascript_name[/^#{File::SEPARATOR}/] ? ASSETS_DIR : JAVASCRIPTS_DIR, joined_javascript_name)
282: 
283:           unless ActionController::Base.perform_caching && File.exists?(joined_javascript_path)
284:             write_asset_file_contents(joined_javascript_path, compute_javascript_paths(sources, recursive))
285:           end
286:           javascript_src_tag(joined_javascript_name, options)
287:         else
288:           expand_javascript_sources(sources, recursive).collect { |source| javascript_src_tag(source, options) }.join("\n")
289:         end
290:       end

You might be able to modify the caching code and run it manually on deploy.

Community
  • 1
  • 1
robotmay
  • 1,318
  • 14
  • 22
  • The wget could work, although some of our assets caches only get generated on logged in pages (one for admins, buyers, sellers, etc) so I don't think a use can login with a simple wget. The write_asset_file_contents method looks promising. If someone has that working from a capistrano deploy that would be interesting. – Brian Armstrong May 11 '10 at 19:55