Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP


Rails 3.1 Asset Pipeline support #35

merged 1 commit into from

8 participants

Chris Griego Lee Hambley Sheldon Hearn Ênio Lopes Alex Ganov Richard Hulse Paco Guzmán Lukáš Konarovský
Chris Griego

I haven't dug into the details yet, but deploying Rails 3.1 will need some special consideration for the new asset pipeline support. I think it will mainly be symlinking a public/assets folder to the shared folder and running a precompile rake task. The tricky thing will be not breaking Rails < 3.1 apps.

Chris Griego

I'm really struggling with figuring out how to handle the rake assets:precompile task. I'm considering requiring the application load a "deploy/assets" recipe to get this functionality.

Chris Griego

There are other tools already in use that have asset compilation steps. Maybe it's as simple as having a variable that defines what the asset pre-compilation rake task is and run it only if it is defined and then update the generated deploy.rb to document it.

Chris Griego

Pull request added. Not the cleanest thing in the world but it's in line with people's expectations of Capistrano 2.x.

Chris Griego

Wait, I forgot about symlinking the assets folder to share unchanged assets across deploys. I think given that part of it, I'll go back to the idea of making it an additional recipe load.

Lee Hambley

Thanks @cgreigo - I'll get to reviewing and merging all these pull requests towards the end of the week, so we'll get something out of the door this month.

Lee Hambley

@sheldonh - thanks I believe I have enough information between you and @cgriego to do a decent job of getting this out of the door this weekend, watch this space for a pre-release :)

Chris Griego

@leehambley I've updated the pull request with a separate recipe that better supports the Rails 3.1 asset pipeline but it doesn't make any attempt to support any other asset compilers. This uses the best practices DHH outlined in his RailsConf keynote (namely the symlinking assets across deploys).

Chris Griego

I'm wondering if deploy:assets:symlink should run on any server with a release and not filter to just web servers. I could go either way.

Lee Hambley
Chris Griego

@leehambley I don't buy it. What makes an asset role distinct? What is a web server if not a server for assets?

Lee Hambley
Chris Griego

Help me understand. I don't see the functional difference between a server with the :web role as capistrano treats it now and an origin server for a CDN.

Ênio Lopes

Is this going to be merged anytime soon?

Lee Hambley
Alex Ganov

When using this patch with bundler/capistrano recipes deploy:assets:symlink failing because the recipes are executed before bundle install. Any way to get bundler's recipe executed before deploy:assets?

Chris Griego

@aganov I'll have to change how the recipe hooks in.

Bundler runs the bundle:install task after deploy:update_code. Right now the assets recipe is running the asset precompile task after deploy:finalize_update which happens in the context of deploy:update_code.

There's no good common hook outside of deploy:update_code though, so the asset task could be changed to also hook in and run after deploy:update_code, but then in order to get the Bundler task to run before the asset recipe, you'll be dependent on the load order of the recipes, which would be pretty problematic in real world use.

load 'deploy'
load 'bundler/capistrano'
load 'deploy/assets'
Lee Hambley
Chris Griego

Unfortunately I don't think there is a sane additional hook to pick here. finalize_update is the sane hook and it already exists. I'm going to make the changes to this patch that allow it to work with Bundler in an load-order-dependent mode and then submit a patch to Bundler to change it to use the proper hook. I trust @indirect will merge it pretty quickly.

Chris Griego

Updated this pull request and sent the pull request to Bundler.


Richard Hulse

You will also need to create a shared cache directory for the cache:

/tmp/cache/assets/ is used as the default cache directory


Otherwise the cache will be lost with each deployment.

Chris Griego

@rhulse Great catch, I'll get that worked in this weekend.

Richard Hulse

Cool. I'll update the asset pipeline docs when it is merged into master.

Chris Griego

I also need to add a variable for the assets path since it can be configured in Rails by setting assets.prefix.

Chris Griego

Removed the cache symlinking because it turns out it is not supposed to be shared.

Lee Hambley

@cgriego - great work on this, please give me a nod when you feel it's ready to be merged (or better yet, collapse the history into one clean commit I can pull) - I'll keep my eyes on this pull req. until such time as it feels like it's calmed down, or you tell me you're happy with it.

Chris Griego

@leehambley Added one small last fix from my testing and I've squashed. It's ready to go.

Richard Hulse

Do you have to set :assets_prefix in the project's deploy recipe, if you are not using the default of 'assets'?

Richard Hulse

Scratch that last comment, there is a bug. You have not use the param #{assets_prefix} every time in lines 23 and 24 of the patch.

This will cause issues for people who are using /assets as shared already. (Cannot offer a patch sorry, not git access from the office).

Chris Griego

@rhulse The assets_prefix variable is used to control the public path only and mirrors the Rails config option. The shared directory is a Capistrano concept and doesn't use the variable by design. The shared directory, being shared across deploys, needs to use stable, reserved names despite changes between users' individual deploys, like changing the prefix from one deploy to the next. No other shared directory name is configurable in the deploy recipe. This won't cause anyone who already has a public/assets directory any problems but it will if they have written custom recipes that setup a shared/assets folder and try to load the assets recipe but if they already have a custom assets system setup then they won't need to load this recipe.

Lee Hambley leehambley merged commit 228d686 into from
Lukáš Konarovský

This is good, but what about not running precompile task, if it is not needed? Example in this blogpost -

@daeltar please feel free to open an issue and/or send a patch (ideally making this configurable) - nothing will change from a commit comment!

Paco Guzmán

@pacoguzman Thank you for your constructive feedback.

Excuse me, that was the first thought after found what broke our deploy. We'll try to figure out a constructive way to solve our problems

Joseph Dilag jdilag referenced this pull request from a commit
Joseph Dilag jdilag Fixed svn.rb fetch_revision
fixed error thrown by line #35 on deployment process
Joerg Sonnenberger jsonn referenced this pull request from a commit in jsonn/pkgsrc
gls Update sysutils/capistrano to 2.8.0
Upstream changelog:

  ## 2.8.0 / August 3 2011

  A short release, after the last. Announcing Rails 3.1 asset pipeline support.

  The asset pipeline support requires an additiona `load` in your `Capfile`.

  You can see information pertaining to the pull request, including the inline
  comments here: capistrano/capistrano#35

  Documentation will be available soon in the wiki.

  * Drop-In Rails 3.1 asset pipeline support. (Chris Griego)

  ## 2.7.0 / August 3 2011

  A fairly substantial release. There are fixes so that current_release works
  during dry-runs, (although, apparently still not with bundler.)

  The test-suite was also modified to work with Ruby 1.9.2, except in one case
  where Ruby 1.9.x calls `to_ary` and `to_a` on mocks, which still makes an
  error. 1.9.x has always been supported, but due to lack of maintenance on my
  part the tests didn't ever pass.

  The `start`, `stop` and `restart` tasks have been reduced to mere hooks into
  which extensions can define their own functionality.

  The `readme` was also slightly improved, simply tweaks to express how best to
  run the test suite.

  * Ensure dry-run works with `:current_release` variable (Carol Nichols)
  * Added a new variable `:git_submodules_recursive`, setting the value to false
  will ensure Git doesn't recursively initialize and checkout submodules. (Konstantin Kudryashov)
  * Added an additional task option, `:on_no_matching_servers`, setting the
  value to `:continue` will ensure tasks with no matched servers continue
  without error, instead of raising `Capistrano::NoMatchingServersError` as was
  the previous behaviour. (Chris Griego)

  A huge thanks to all contributors, as always!

  Remember: @capistranorb on twitter for news.

  ## 2.6.1 / June 25 2011

  A short maintenance release, Some fixes to the verbose flag inside the Git SCM
  as well as another argument for the (internal) `variable()` command, offering
  a default. The Git SCM is now verbose by default, but can be disabled by
  setting `:scm_verbose` to false.

  There has been an additional method added to string, within the context of the
  test suite, I'm always sketchy about adding additional methods to core
  classes, but it's a short term fix until I make the time to patch the test
  suite not to compare strings literally. The method is `String#compact`, and is
  implemented simply as `self.gsub(/\s+/, ' ')`.

  Here's the run-down of changes, and their committers, as always - a huge thank
  you to the community that continues to drive Capistrano's development.

  * `deploy:setup` now respects `:group_writable` (Daniel Duvall)
  * Fixes to `:scm_verbose` for the Git module (defaults to On.) (Matthew Davies)
  * Will now copy hidden files in the project's root into the release
  directory (Mark Jaquith)
  * Now handles closing already-dead connections in a sane way (does not raise
  an exception) (Will Bryant)
  * Renamed `Capistrano::VERSION::TINY` to `Capistrano::VERSION::PATCH` (Lee
  * Removed the `VERSION` file (Lee Hambley)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 20, 2011
  1. Chris Griego
This page is out of date. Refresh to see the latest.
4 bin/capify
@@ -38,6 +38,10 @@ end
files = {
"Capfile" => unindent(<<-FILE),
load 'deploy' if respond_to?(:namespace) # cap2 differentiator
+ # Uncomment if you are using Rails' asset pipeline
+ # load 'deploy/assets'
Dir['vendor/gems/*/recipes/*.rb','vendor/plugins/*/recipes/*.rb'].each { |plugin| load(plugin) }
load 'config/deploy' # remove this line to skip loading any of the default tasks
8 lib/capistrano/recipes/deploy.rb
@@ -28,7 +28,9 @@ def _cset(name, *args, &block)
_cset(:deploy_to) { "/u/apps/#{application}" }
_cset(:revision) { source.head }
-# Maintenance base filename
+_cset :rails_env, "production"
+_cset :rake, "rake"
_cset :maintenance_basename, "maintenance"
# =========================================================================
@@ -384,8 +386,6 @@ def try_runner(*args)
set :migrate_target, :latest
task :migrate, :roles => :db, :only => { :primary => true } do
- rake = fetch(:rake, "rake")
- rails_env = fetch(:rails_env, "production")
migrate_env = fetch(:migrate_env, "")
migrate_target = fetch(:migrate_target, :latest)
@@ -395,7 +395,7 @@ def try_runner(*args)
else raise ArgumentError, "unknown migration target #{migrate_target.inspect}"
- run "cd #{directory}; #{rake} RAILS_ENV=#{rails_env} #{migrate_env} db:migrate"
+ run "cd #{directory} && #{rake} RAILS_ENV=#{rails_env} #{migrate_env} db:migrate"
desc <<-DESC
57 lib/capistrano/recipes/deploy/assets.rb
@@ -0,0 +1,57 @@
+load 'deploy' unless defined?(_cset)
+_cset :asset_env, "RAILS_GROUPS=assets"
+_cset :assets_prefix, "assets"
+before 'deploy:finalize_update', 'deploy:assets:symlink'
+after 'deploy:update_code', 'deploy:assets:precompile'
+namespace :deploy do
+ namespace :assets do
+ desc <<-DESC
+ [internal] This task will set up a symlink to the shared directory \
+ for the assets directory. Assets are shared across deploys to avoid \
+ mid-deploy mismatches between old application html asking for assets \
+ and getting a 404 file not found error. The assets cache is shared \
+ for efficiency. If you cutomize the assets path prefix, override the \
+ :assets_prefix variable to match.
+ task :symlink, :roles => :web, :except => { :no_release => true } do
+ run <<-CMD
+ rm -rf #{latest_release}/public/#{assets_prefix} &&
+ mkdir -p #{latest_release}/public &&
+ mkdir -p #{shared_path}/assets &&
+ ln -s #{shared_path}/assets #{latest_release}/public/#{assets_prefix}
+ end
+ desc <<-DESC
+ Run the asset precompilation rake task. You can specify the full path \
+ to the rake executable by setting the rake variable. You can also \
+ specify additional environment variables to pass to rake via the \
+ asset_env variable. The defaults are:
+ set :rake, "rake"
+ set :rails_env, "production"
+ set :asset_env, "RAILS_GROUPS=assets"
+ task :precompile, :roles => :web, :except => { :no_release => true } do
+ run "cd #{latest_release} && #{rake} RAILS_ENV=#{rails_env} #{asset_env} assets:precompile"
+ end
+ desc <<-DESC
+ Run the asset clean rake task. Use with caution, this will delete \
+ all of your compiled assets. You can specify the full path \
+ to the rake executable by setting the rake variable. You can also \
+ specify additional environment variables to pass to rake via the \
+ asset_env variable. The defaults are:
+ set :rake, "rake"
+ set :rails_env, "production"
+ set :asset_env, "RAILS_GROUPS=assets"
+ task :clean, :roles => :web, :except => { :no_release => true } do
+ run "cd #{latest_release} && #{rake} RAILS_ENV=#{rails_env} #{asset_env} assets:clean"
+ end
+ end
Something went wrong with that request. Please try again.