Conditionally disable asset precompile in Capistrano - ruby-on-rails

I've seen various convoluted and generally ineffective solutions to performing lazy asset precompile in Rails. As a backend developer I don't particularly want to recompile assets I never touch every time the program deploys, but because assets are loaded in Capfile via load 'deploy/assets', and not by defining a task in deploy.rb, I can't think of a way to conditionally disable it.
The behaviour I'm after is to use cap deploy for regular with-precompile deployment, and to use cap deploy:no_assets to skip asset deployment.

Both turbo-sporocket-rails and the that auto-skip scripts have some pitfalls (I will mention later). So I use the following hack, so I can pass a parameter to skip asset pre-compile at my will:
callback = callbacks[:after].find{|c| c.source == "deploy:assets:precompile" }
callbacks[:after].delete(callback)
after 'deploy:update_code', 'deploy:assets:precompile' unless fetch(:skip_assets, false)
This script will change the built-in asset-precompile hook, so it will be hooked based on the skip_assets parameter. I can call cap deploy -S skip_assets=true to skip asset precompile as a whole.
For me, turbo-sporocket-rails still takes minutes to do the checking when nothing has changed. This can be crucial when I need to push a fix to the server asap. Therefore I need my force-skipping method.

rails4 addresses this issue with it's new version of sprockets, by only precompiling assets that have changed. In the mean time, for your rails3 apps I recommend the turbo-sprockets-rails3 gem.
This gem started out as a set of patches for sprockets-rails by Nathan Broadbent, which were not merged into master because the problem was already addressed in rails4. From the README:
Speeds up your Rails 3 rake assets:precompile by only recompiling changed assets, based on a hash of their source files
Only compiles once to generate both fingerprinted and non-fingerprinted assets
And:
turbo-sprockets-rails3 should work out of the box with the latest version of Capistrano.
I can confirm that it works well for me on rails-3.2.x apps deploying with Capistrano.
As a side note for GitHubbers, the original pull request is an excellent example of how to submit code to an open source project, even if it wasn't merged.

This gist looks very promising https://gist.github.com/3072362
It checks your git log from the last deploy to now to see if there are any changes in %w(app/assets lib/assets vendor/assets Gemfile.lock config/routes.rb) and if so, only precompiles then.

Related

heroku precompile assets is it necessary

I've started learning rails and I've already built two apps, one simple blog app and one store app. Now I ran into a term precompile assets when uploading to heroku, can someone explain it to me is that necessary when deploying an app to production, because i've uploaded my store app to heroku without any problems?
Assets is your css + JS. Precompile assets mean that they get joined into single .css and another single .js. file (to load it in one HTTP request). And special mechanism of minifying get applied to both these files (to make them smaller). Rails by default is setup in a way, that it uses average files in dev and compiled files in prod. You can easily change this in configs, but you shouldn't do this unless you really know what you do.
If you want you can compile this files locally running rake assets:precompile and then put it into git. I think that you can disable/enable precompile during heroku deploy in heroku config. But, in general, I would stick with the very defaults.
More info on asset pipeline: http://guides.rubyonrails.org/asset_pipeline.html
Rails has an assets pipeline which consists of Sprockets and the assets helpers.
The assets pipeline will concat and minify your CSS and javascript and takes care of setting the correct paths to images and other assets. This is known as compiling the assets.
In development this is done on the fly for each request which lets you immediately see changes.
In production this would be far to slow so instead the assets should be compiled once at deploy time. Heroku does this automatically for you in a post-commit hook.
Pre-compiling is when you run rake assets:precompile locally and then upload or push the result to a server. This is done if you are deploying to a server without the support for the assets pipeline. For example if the production server does not have a javascript runtime which is required to run uglifier.
It adds tons of noise to the git change history and manually doing anything is a common source of user error. So pretty much it sucks and you only do it if you have to.

Rails not precompiling images in the app/assets/images folder?

I have some images (svg) in my app/assets/images folder. According to the Rails Guides, all the files in the assets folder should be automatically precompiled.
However, when I reference the the image using image_tag('filename'), it shows me an Sprockets::Rails::Helper::AssetNotPrecompiled error
Asset was not declared to be precompiled in production.
It tells me to declare the file to be precompiled manually, but why should that be necessary? On top of that, why does it concern itself with the production environment when I am doing everything in development?
If you added the image after you've started the server in development, restart the server. Sprockets will then precompile that image and the error will go away.
I'm pretty sure Rails doesn't support .svg yet, hence why it would ignore it.
You'll need to include the file extensions in your config/application.rb file:
#config/application.rb
config.assets.precompile += %w(.svg)
In regards the application concerning itself with the production environment, you have to remember that the precompilation process is meant for production:
The first feature of the pipeline is to concatenate assets, which can reduce the number of requests that a browser makes to render a web page. Web browsers are limited in the number of requests that they can make in parallel, so fewer requests can mean faster loading for your application.
Concantenating assets essentially means to compile your asset files into a single file, which is typically then minified.
--
Although this can be done in real-time, it's mostly the realm of static assets (which have to be precompiled). This means that if you run the rake asstes:precompile task, it will work on the development environment, unless you call RAILS_ENV=production rake assets:precompile (which sets it to the production environment for that request.
why does it concern itself with the production environment when I am doing everything in development
The application is going to run in production, not development.
Ultimately, everything you do in development should make it easier / better to work in production. In the sense of your assets, it means that you can use many of the quirks of Rails' asset pipeline, from sprockets to preprocessors such as SASS & Coffeescript
It's probably because you didn't specify the complete image name. I ran into this problem after updating the gem too. Before I just used image_tag 'some-image', but it seems that you now have to specify what type of image/extension you want to use.
Try this: image_tag 'some-image.svg'. It worked for me.
Cheers.

Rails 3.1.1 asset pipeline Heroku caching gotcha

The problem in a nutshell is that in development mode we'd make changes to CSS or JS files but would always get cached/old versions of these files. Nothing I did had any effect. I checked configuration dozens of times and tried every combination of config values but always kept getting the same results: stale/cached files. I had to actually run in production mode and restart the server after every change to test.
I spent days tearing my hair out over this issue, looked at dozens of stackoverflow questions on the asset pipeline but never found one that addressed it so I thought I'd post it here for posterity.
We use Heroku and precompile our assets because Heroku fails to precompile for us (we also use devise which apparently is the cause of the heroku precompilation failure). So in order to push our precompiled assets up to Heroku we have to check them in to git.
Here's the problem.
When we upgraded to Rails 3.1.1 asset precompilation produced files both with and without the MD5 hash in the name. I didn't think much of this and went ahead and checked all these files in so I could push to heroku. Sometime later I noticed the problem with cached results in development mode. The precompiled and checked in assets without the MD5 hashes were being served from /public/assets as static files which prevented us from seeing any changes we were making in /app/assets.
After finally realizing this I ran git rm /public/assets and everything works again. So the takeaway is: Be careful checking assets into git!
To turn this into a question: how do others do this? Am I missing something obvious? What I'd really like is for Heroku to precompile my assets for me but it is failing with a db connection error that I gather is because of devise. I had hoped Rails 3.1.1 fixed this but it didn't.
Have you checked out this devise issue on github? Specifically Jose Valim says
Rails 3.1.1 final has a method called
config.assets.initialize_on_precompile. If you set it to false, you
should be good but it won't allow you to access model information on
your assets (which you probably shouldn't anyway).
Maybe this will allow the precompile to happen on Heroku for you.
The reason the asset precompilation does not work could well be, that the Heroku ENV vars are not present on slug compilation (deploy) as stated here:
http://devcenter.heroku.com/articles/rails31_heroku_cedar
There is an (experimental) way to enable the ENV vars during deploy for exactly this reason, find information here:
http://devcenter.heroku.com/articles/labs-user-env-compile
Hope this helps.
Check this guide from Heroku. It outlines the 3 ways to deploy Rails 3.1 apps. Two of these do not required local precompilation.

Do you add public/assets in version control?

In rails 3.1, when you precompile the assets, rails create public/assets directory and add files there.
Do you version-control public/assets/*?
I use Capistrano to deploy. The last step is compiling the assets. Nothing like that gets checked into version control.
https://github.com/capistrano/capistrano/wiki/Documentation-v2.x
Checking in compiled assets, .gz files/etc, will just clutter up version control.
I was looking for an answer to this too. I found the official Rails Guide has some thoughts on this:
http://guides.rubyonrails.org/asset_pipeline.html#local-precompilation
Here's a quote of the relevant section (emphasis added):
There are several reasons why you might want to precompile your assets locally. Among them are:
You may not have write access to your production file system.
You may be deploying to more than one server, and want to avoid duplication of work.
You may be doing frequent deploys that do not include asset changes.
Local compilation allows you to commit the compiled files into source control, and deploy as normal.
There are three caveats:
You must not run the Capistrano deployment task that precompiles assets.
You must ensure any necessary compressors or minifiers are available on your development system.
You must change the following application configuration setting:
In config/environments/development.rb, place the following line:
config.assets.prefix = "/dev-assets"
The prefix change makes Sprockets use a different URL for serving assets in development mode, and pass all requests to Sprockets. The prefix is still set to /assets in the production environment. Without this change, the application would serve the precompiled assets from /assets in development, and you would not see any local changes until you compile assets again.
In practice, this will allow you to precompile locally, have those files in your working tree, and commit those files to source control when needed. Development mode will work as expected.
So, it looks like it might be a good idea to put precompiled assets into VCS on occasion.

How do you catch errors in the rails asset pipeline before production?

I'm just getting acquainted with Rails 3.1, and I burned some time updating an old project and trying to work out how the new asset pipeline behaves in development mode versus production.
The default config.assets.precompile setting blesses only application.css and application.js, with the intention that everything should be served as a single stylesheet and a single javascript file.
Obviously there are situations when we don't want that, so we can add items to the list in that config variable...
Here's the situation I ran into with my sandbox project when going to production:
Browsed the site in development, saw that everything was working. The assets were linked as separate files and the site displayed correctly.
Uploaded the site to my server, and tried to get it working in production. The first error was saying that "ie.css" (a conditional stylesheet) isn't precompiled. (I was in Safari and this stylesheet wouldn't even be downloaded: the error was raised from the stylesheet_link_tag helper before rendering the page.)
Ran rake assets:precompile and tried again.
Added the offending item to config.assets.precompile and tried again.
Kicked the error down the curb until it hit another asset error.
GOTO 3.
Not knowing how to address this, I went around in circles a few times until I thought I got all the assets and the site was rendering in production. Then I tried it in MSIE and hit another error 500: "belated_png_fix.js" was being conditionally loaded, and it didn't crop up until then.
So my question is, other than trial and error or a heavy dependence on integration testing, how can I predict that my site isn't going to bomb out when the asset pipeline discovers that some stylesheet or javascript wasn't added to the precompile list?
I'm also curious why a missing stylesheet asset should cause the whole page to error 500 instead of just compiling it on-demand or serving a 404 when that asset is requested. Is this a deliberate design to "fail early"?
I've just released a gem called assets_precompile_enforcer, which ensures that developers won't forget to add assets to config.assets.precompile while they are developing. An exception will be raised if you include an asset via javascript_include_tag or stylesheet_link_tag, and it doesn't match a filter in config.assets.precompile.
This means that asset errors will be caught during development, instead of being discovered after deploying to production.
I had similar problems with rails 3.1 as well. The best thing you could do is to install capistrano multi stage and get a staging server.
If for any reasons this is not possible, install a virtual machine on your computer and try to replicate your servers environment.
Continuous deployment is a great thing, and you should get to the point where it is so simple that it really isn't that painful anyway. That being said, config.assets.precompile can take regexs, so how about you come up with a standard for top level sprockets "manifest" files, or a standard sub folder for things that will not be bundled up? (note that I haven't actually tried this yet...)
This may be overkill, but this works for me (it gives me clean, compiled assets). I have this in my .bash_profile file.
alias ggo='bundle exec rake assets:clean && bundle exec rake assets:precompile && git add . && git commit -m "precompile" && git push origin master && cap deploy'
and this in my config/environments/production.rb (forces production to compile when needed; shouldn't be a need to if I remember to run "ggo" first):
config.assets.compile = true
So, my workflow is:
1. code
2. git add & git commit
3. if I touched CSS/SASS/JS/CoffeeScript files, I run ggo. Otherwise, I do a normal cap deploy.

Resources