Make rake assets:precompile:nondigest optional #5379

wants to merge 8 commits into


None yet

(for applications with fully digested assets)

  • Improves speed of precompile significantly.
  • Therefore improving speed of deployments OOTB on Heroku etc.
  • assets:precompile:nondigest task still runs in Rake and warning issued
  • as Rake task still runs, rake task enhancements still possible
  • config.assets.nondigest_enabled setting disregarded if not present (backwards compatibility)

This is actually in reference to a ticket I raised 5 months ago that is still open #3419

All of our applications on Rails 3 are fully using digested assets. With this patch it allows us to shave some time off of every deployment!


Tks for the pull request but I don't think we should be working around Heroku limitations in this specific scenario. We already have a task that does exactly what you ask.


@josevalim I know, there are separate tasks already. My motives for this pull request are not to workaround heroku limitations, but instead good defaults.

Most PaaS services I've seen are focusing on integration with rake assets:precompile as the default.

Sure on some platforms it means simply just changing a rake task that gets executed. On Heroku for example, I'd need to configure all of those apps with custom build packs (not so simple).

So, it would be great that this is just handled by a configuration setting in Rails so the only task need run is rake assets:precompile in all scenarios.

This is also great for extensions to the asset pipeline for example asset_sync where we are now relying on integrating with certain tasks in the pipeline compilation because of how Kernal.exec is being used.

In my opinion having one way of compiling assets makes things a lot simpler (to the end users). As it doesn't matter what my configuration is (wether I use digests or nondigest assets) my deployment processes are still the same.


+1 for good defaults




A build pack is not the only solution here. Heroku could support an environment variable or a config to customize it.

And I don't think people should actually hook into assets:precompile because the assets precompile task doesn't actually generate anything (it seems assets sync hooks in both tasks, I need to take a better look).

Maybe it would be fine to have an env option to disable non digest. I don't think it belongs to config.assets.


please don't merge this (yet), I'm finishing the extraction of sprockets-rails from rails (probably I will finish it today)


@guilleiguaran awesome!

@josevalim thanks.

I choose to implement this with Rails config vs ENV config based on the fact that the behaviour of rake assets:precompile is already influenced by the Rails config. I think this is the best approach as it means no matter where I run rake assets:precompile the result will be the same.

In my mind the config.assets.digest should determine wether to run precompile:primary or precompile:nondigest not both. The only reason we're doing both is to help people who haven't got all their asset references fixed to return the digested links in all aspects of their application... have I got that right? I've found that's great for bootstrapping a migration of a Rails 3.0 to 3.1 application. However it's really not helping people if they start using a CDN and are referencing nondigest assets unknowingly. It's much better if this fails fast and is fixed on a first deploy to a staging setup.

That's my opinion, and was my first port of call for implementing this but I thought it would be a much more difficult change, that's why I put together this patch which offers all the existing functionality and unobtrusively allows "taking off the training wheels" when you don't need them :)

Whilst it would be less preferable, I'd be up for reworking this to use ENV variables if that was the consensus!

Regarding asset_sync if I've made a mistake in our integration, I'm all ears. We're not actually hooking into both tasks: as of 0.3.0 (Rails 3.2.x) we're enhancing only the assets:precompile:nondigest task as it will always be ran and ran last.

Due to how the usage of Kernal.exec was introduced. We stopped enhancing the assets:precompile task but left it in the default Rake task for backwards compatibility with Rails 3.1.x releases to kick in only if the assets:precompile:nondigest task does not exist. Rather than sniffing Rails versions specifically.

I actually already fired a mail to Heroku for their thoughts on this. I totally agree, I'd love if their deployment strategies were a lot more customisable too.


The only reason we're doing both is to help people who haven't got all their asset references fixed to return the digested links in all aspects of their application... have I got that right?

The reason we are compiling both is because some times it is hard to access the digest version, like in emails, errors pages and other static pages. Indeed, referencing an asset without digest by accident is unfortunate, but removing the non digest version is the wrong answer to this problem.

That said, I don't feel strong about this feature but I am fine with an ENV variable since it feels less intrusive than adding a new option to config.assets.


Ok, I just got feedback from other Rails Core Members and some of them are actually interested in this feature. But we need a few changes to make everything work well. If you are up to the challenge we can work on this together, I can provide any guidance you need. Here are the concerns:

  1. We would need to move 500.html, 404.html and friends to app/assets so they would be able to use the digested version of the assets;

  2. I think development accepts both /assets/email.png and /assets/DIGEST-email.png. This is bad because if you accidentally use the non digest version in development, you will just catch the error in production;

If we can fix those two points, I believe we can change how this rake task behaves for Rails 4 to not include the non digest versions by default. If someone want the digest version, they can run rake assets:precompile:nondigest manually. Wdyt?


Great. Can help out on this for sure.

Both those points, I agree. If you've any ideas on implementing would be good to hear. Any existing tickets out there with further info?

I'll look into 2) though it sounds easy enough.

Biggest concern would be 500.html and 404.html. I've had a think about how this should work...

  • Create a new assets directory app/assets/static
  • .html files in this directory are pre-processed / rendered (to allow .erb, .haml) extensions etc.
  • Generate defaults like app/assets/static/404.html.erb
  • files receive same scope for rendering as other assets to allow for digests
  • files are rendered to public/assets as normal
  • some special handling in the default error handler to render public/assets/404-DIGEST.html instead of public/404.html

Does that sound about right? not sure at the minute if there'd be much of an impact on routes or .htaccess files?

soffes commented Mar 11, 2012

@davidjrice that sounds amazing! I basically do that now, only all manually. This would be great.


Yes, the default error handler will need to be improved. Here is the current implementation:

For me, the biggest concern regarding 2) is: can it be an issue for many applications if the 404 page is actually hidden under assets/404-DIGEST.html? Well, if there is an issue they could use assets:precompile:nondigest to get both versions, I am just wondering if this would be the common case or the exception.

@jeremy: you commented that we could also include robots.txt at app/assets/static, but given that assets are compiled to public/assets, that wouldn't actually work. Any ideas in mind? Maybe we could tell sprockets that all files at app/assets/static should actually go to public/ ? Is it a good idea?

jeremy commented Mar 12, 2012

They should probably still generate digested assets in public/assets then symlink in from public/ so 404.html, robots.txt, etc always reference the latest file.

What do you think about a dir for "root" assets, like app/assets/static or app/assets/public?


@jeremy @josevalim I've put together a first pass at getting this to work. I've slightly cheated and used a static middleware to lazily serve content in app/assets/public for development mode. Main bit I'm unsure about for now is how to get the static assets rendering with a .erb extension if present.

Would you suggest a custom middleware?

I still need to ensure referencing assets without a digest in emailers fails correctly.


@davidjrice the pull request is "dirty". Could you please rebase it?

davidjrice added some commits Mar 11, 2012
@davidjrice davidjrice Make rake assets:precompile:nondigest optional (for applications with…
… fully digested assets)

* Improves speed of precompile significantly.
* Therefore improving speed of deployments OOTB on Heroku etc.
* assets:precompile:nondigest task still runs in Rake and warning issued
* as Rake task still runs, rake task enhancements still possible
* config.assets.nondigest_enabled setting disregarded if not present (backwards compatibility)
@davidjrice davidjrice Move all static assets from /public to /app/assets/public in Railties
Also remove stylesheets directory and make public an empty dir
@davidjrice davidjrice Generated public directory should have a .gitkeep, add static middlew…
…are to serve app/assets/public in development mode only
@davidjrice davidjrice Only apply app/assets/public middleware if config.serve_static_assets 0d8112d
@davidjrice davidjrice Symlink all assets generated from app/assets/public into public 1d0ea03

@josevalim sorry, my bad, fixed this now.


@davidjrice thanks! Although I am skeptical about symlinks since they don't work on windows. We would need to check for alternatives on windows. Adding another middleware for app/assets/public also feels weird and as you said it will cause issues for rendering ERB files.

@jeremy any ideas on solving those issues?

  • We could just copy the file to public on windows
  • The additional static middleware for app/assets/public is only a temporary POC hack :)
  • A middleware that would generate them from ERB if a .html.erb extension exists or simply serve the static file if it doesn't would be preferable... i'm just not sure of the best way of doing this yet.

@davidjrice Since it is inside app/assets, a developer would expect not only .erb to work, but also .haml and so on.

Ideally I would pipe the request to sprockets and let sprockets do its thing but afaik there is no way for us to tell sprockets to serve only assets for public.

davidjrice added some commits Mar 13, 2012
@davidjrice davidjrice Only include app/assets/public static middleware when necessary. Impr…
…ove public exceptions middleware to render from app/assets/public as a fallback

* Include app/assets/public static middleware only (if config.serve_static_assets && config.assets.enabled && config.assets.compile) or in development mode
* Exception middleware checks public first and falls back to app/assets/public
@davidjrice davidjrice Improve public exception middleware, add attr for assets_public_path 067a73c
@davidjrice davidjrice When symlinking files under assets:precompile handle if there are alr…
…eady existing symlinks by unlinking them first

@josevalim yeah handling erb, haml etc. would be best.

Thought about integrating with sprockets, not sure where to start with that. (if anyone has any ideas I'd love to hear!)

It's possibly something that needs to go into sprokets-rails though?


Let's summon @josh and @sstephenson and see if they have any ideas/feedback about this.

josh commented Mar 13, 2012

The amount of flags and options in rails for the asset stuff is insane now.

Just put your "nondigest" stuff in public.


@josh I know, the flag initially introduced at the start of this pull request was only intended to be an unobtrusive addition so as not to affect any existing functionality.

However after discussing with @josevalim the direction I am now heading towards is moving all the default rails static assets in public to within the asset pipeline so they may be precompiled. Being able to have these files as part of the application, pre-generated on deployment offers some great flexibility.

This could be taken a step further with the functionality I describe in this comment. Which would make rake assets:precompile:all and the new config I proposed unnecessary and rake assets:precompile would simply run either digest or nondigest only, depending on the setting of config.assets.digest. This would in turn simplify the assets:precompile task itself and not require shenanigans with Kernal.exec and would speed up execution.


Closing this here since Sprockets integration was extracted from Rails edge and this couldn't be done in 3-2-stable. Please re-open your PR in sprockets-rails to continue the discussion (and please reference this PR)


Guillermo, this needs opened again in my opinion as there are components to go into both rails and sprockets-rails

@guilleiguaran guilleiguaran reopened this Apr 27, 2012
homakov commented Jun 8, 2012

@davidjrice just noticed. keep it up - it will also fix #6421


Someone can elaborate a good reason to keep non-digested assets outside of public?

Like @josh I would prefer move non-digested stuff to public and compile only digested version of stuff in app/assets


@guilleiguaran think you missed the whole point. If your read the above discussion again you'll see the goal is to generate files such as 404.html at precompilation time.

This allows usage of digested asset paths in 404/500 etc.
This also simplifies the whole digest / non-digest precompilation step and therefore reducing compilation time by 50%

As the last remnants of public/ are static files, however they need treated differently from assets as they are usually used on the server the rails app is served from, as opposed to assets which predominantly get shuffled to an asset host


Hi, what do you think about #7866 as an alternative solution?

This patch means that only digest assets would be compiled, and non-digest assets are generated from those in only a few milliseconds. In that case, there would probably be no need to make them optional.

@davidjrice - I've also released these changes in a gem for Rails 3.2.8, at I would be grateful if you could try it out and let me know if it solves your problem with long deployments.


@ndbroadbent as mentioned, in #7866 I don't think it's an alternative solution. More of an extension to what I have here. I would definitely want a combination of the two in Rails 4!

The goal of this pull request should probably be restated that it is to Move the remaining rails public directory assets into the asset pipeline

josh commented Oct 10, 2012

The goal of this pull request should probably be restated that it is to Move the remaining rails public directory assets into the asset pipeline


@route route referenced this pull request in rails/sprockets-rails Oct 18, 2012

Last sprockets changes #9


Because sprockets-rails was moved out of master, there's no way this is going in. Therefore, I'm closing. Please re-submit to sprockets-rails and/or a backport fix to 3-2-stable.

@johnnyshields johnnyshields referenced this pull request in rails/sprockets-rails Nov 13, 2013

Ability to skip non-digest assets? #97


Just a note for those who arrive here via Google: sprockets-rails (used in Rails 4.0.0+) no longer compiles non-digest assets.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment