I am hosting my assets on s3. In production, rails is looking for /javascripts/cache/all.js and /stylesheets/cache/all.css. I'm using a plugin to swoop the public directory over to s3 when I deploy with cap. The problem is that rails doesn't create these cache files until they are requested for the first time, so they aren't around during deployment when I transfer the public dir. Is there an easy way to force the creation of these files during deployment?
5 Answers
The actual rails module that creates the cache files is ActionView::Helpers::AssetTagHelper
which you may be able to re-use to create the cache files during deployment. The following worked okay for me:
require 'action_view'
class AssetCacheWriter
include ActionView::Helpers::AssetTagHelper
def write
write_asset_file_contents(File.join(JAVASCRIPTS_DIR, "all.js"), compute_javascript_paths([:all], true))
write_asset_file_contents(File.join(STYLESHEETS_DIR, "all.css"), compute_stylesheet_paths([:all], true))
'standard_all')
end
end
Both those write_asset_file_contents
calls I've lifted from the rails code. The _DIR
constants are defined in the included module and the true
parameters in the compute_xxx_paths
calls indicate that all files should be included recursively.
I created a simple cap task that just wrote the files out:
namespace :sample
task :assets do
AssetCacheWriter.new.write
end
end

- 34,314
- 14
- 94
- 99
I use this in a rake task file. Saves you from creating an additional class and you keep it DRY because you're using the values from the stylesheet_link_tag / javascript_include_tag
desc "Clears javascripts/cache and stylesheets/cache" task :clear => :environment do
puts "Clearing javascripts/cache and stylesheets/cache"
FileUtils.rm(Dir['public/javascripts/cache_[^.]*']) # use :cache => 'cache_all.js' in stylesheet_link_tag
FileUtils.rm(Dir['public/stylesheets/cache_[^.]*']) # use :cache => 'cache_all.css' in javascript_include_tag
end
desc "Recreate the javascripts/stylesheets cache."
task :generate => [:environment, :clear] do
puts "Recreate the javascripts/stylesheets cache"
ActionController::Base.perform_caching = true
app = ActionController::Integration::Session.new
app.get '/'
end

- 148
- 1
- 5
If you're using Engine Yard Cloud, this is what I did:
added a file /lib/tasks/assetcache.rake
require 'assetwriter'
namespace :assetcache do
desc "Clears javascripts/cache and stylesheets/cache"
task :clear => :environment do
puts "Clearing javascripts/cache and stylesheets/cache"
FileUtils.rm(Dir['public/javascripts/cache_[^.]*'])
# use :cache => 'cache_all.js' in stylesheet_link_tag
FileUtils.rm(Dir['public/stylesheets/cache_[^.]*'])
# use :cache => 'cache_all.css' in javascript_include_tag
end
desc "Recreate the javascripts/stylesheets cache."
task :generate => [:environment, :clear] do
puts "Recreate the javascripts/stylesheets cache"
AssetCacheWriter.new.write
end
end
then I added /lib/assetwriter.rb
require 'action_view' class AssetCacheWriter
include ActionView::Helpers::AssetTagHelper
def write write_asset_file_contents(File.join(JAVASCRIPTS_DIR, "cache/all.js"), compute_javascript_paths([:all], true)) write_asset_file_contents(File.join(STYLESHEETS_DIR, "cache/all.css"), compute_stylesheet_paths([:all], true)) end
end
then I added to /deploy/after_restart.rb
run "cd #{release_path} && bundle exec rake assetcache:generate"

- 11
- 1
I found that include order mattered (so, for example, jQuery is included before other scripts) and so used the below approach instead. Also allows for the use of :defaults.
First lib/asset_pacakger:
require 'action_view'
class AssetCacheWriter
include ActionView::Helpers::AssetTagHelper
include ActionView::Helpers::TagHelper
def write
ActionController::Base.perform_caching = true
stylesheet_link_tag *ApplicationController::STYLESHEET_INCLUDES
javascript_include_tag *ApplicationController::JAVASCRIPT_INCLUDES
end
end
Then scripts/package_assets:
#!/usr/bin/env ruby
RAILS_ROOT = File.expand_path(File.dirname(__FILE__) + '/../')
Dir.chdir(RAILS_ROOT)
RAILS_ENV = ENV['RAILS_ENV'] || 'development'
puts "Bundling assets for environment #{RAILS_ENV}"
require File.join('config', 'environment')
AssetCacheWriter.new.write
Then a cap task:
desc "Package assets"
task :package_assets do
%x[#{Dir.getwd}/script/package_assets]
%x[svn commit #{Dir.getwd}/public/javascripts/defaults.js #{Dir.getwd}/public/stylesheets/defaults.css -m "(capistrano) packaging assets to trunk"]
logger.info "packaged assets to trunk"
end

- 550
- 6
- 14
In Rails 3.0.7 none of the above approaches seemed to work. I got many errors about config being undefined.
After getting my hands dirty looking over the Rails code, I came up with this solution that is working for me.
lib/tasks/cache_assets.rake
require 'asset_packager'
desc "cache assets"
task :cache_assets do
puts "-----> Caching Assets"
AssetCacheWriter.new.write
puts "-----> Done!"
end
And then lib/asset_packager.rb
require 'action_view'
class AssetCacheWriter
include ActionView::Helpers::AssetTagHelper
include ActionView::Helpers::TagHelper
def config
ApplicationController
end
def controller
ApplicationController
end
def write
ActionController::Base.perform_caching = true
# You can replace these with your app's cached assets. They should look the same
# as in your view templates.
stylesheet_link_tag :vendor, :defaults, :cache => 'cached/all'
javascript_include_tag :bd_defaults, :'vendor-head', :cache => 'cached/defaults_vendor'
end
end
Then to execute it, just run rake cache_assets

- 9,604
- 2
- 22
- 18