Rails 3.1, asset pipeline: no route matches - ruby-on-rails

This question is similar to Why do I get “no route matches” for requests to the asset pipeline?.
I have a rails 3.0 application that I upgraded to 3.1 and converted to use the new asset pipeline (thanks to RailsCasts #282 and #279).
In production mode, I'm seeing the application-<digest>.js and application-<digest>.css. Great! And if I look at the source of those files, I see they are compressed. Yee-haw! So that means the asset pipeline is working, right?
However, if I add ?debug_assets=1 to the URL so that I may view individual files, some of them are producing ActionController::RoutingError (No route matches [GET] "/assets/<filename>-<digest>.js"), and same goes for some CSS files. But not all, just some, and I can't figure out what makes some files do this and others not.
I've cleared out tmp/cache/* and restarted Passenger. I've bumped config.assets.version. I've restarted memcached. None of these seem to resolve it. But what's odd is this only comes up when I'm using ?debug_assets=1 in the URL; without it, I see just one JS and CSS file, all compressed and minified.
I don't use precompiled assets, by the way. But just for grins, I performed a rake assets:precompiled, and whaddya know? The ?debug_assets=1 now shows all JS and CSS files, and none of them are 404'd.
So I guess the question you might have is, "Why not just use precompiled assets and not worry about missing assets from lazy load?" Good point. Answer: I just like to make sure I understand what I am doing, what's happening, and that I'm doing things correctly.
application.rb:
config.assets.enabled = true
config.assets.version = '1.2'
production.rb:
config.assets.compress = true
config.assets.compile = true
config.assets.digest = true
config.assets.js_compressor = :uglifier
config.assets.css_compressor = :scss
development.rb:
config.assets.compress = false
# I keep this off during development because I want
# to make sure the compression isn't breaking my JS
config.assets.debug = false

If you precompile your assets and set compile to false, debug is disabled because you've told Rails to not use Sprockets at all, but assumes that the files can be served by nginx based on mappings in the asset pipeline manifest.
When compile is true (like you have) then requests for these assets (and the debug request) are sent back to Sprockets to be processed if the files are missing (which without being precompiled is the case).
I would have assumed Sprockets would serve the individual files for each digested name. This behavior sounds buggy to me, although I don't think it is intended to use debug in production anyway.

Related

Rails 5 - Is there a way to log cache misses?

Trying to debug why we're getting cache misses. In config/environments/production.rb we have asset fallback to true:
config.assets.compile = true
Every once in a while we see CPU surges and the culprit is nodejs, which we believe is firing due to this line (it's compiling assets when there's a miss). Is there a way to log, either to the production log, or it's own, when an asset is missed, so we can figure out why it's not being added to the precompile locus?
Thanks for any help,
Kevin
The directive you mentioned is for asset compiling, not caching. The config.rb directive for caching is (https://guides.rubyonrails.org/caching_with_rails.html)
config.action_controller.perform_caching = true|false
This will not affect the caching of your static assets though, such as images, javascript files, or stylesheets. For that, you need to look at your web server settings and see why your static assets aren't being cached properly. You indicated that you get a spike once in a while. Are the spikes consistently spaced apart? If so then it may just be that your cache time to live is set too low and you need to bump it up. Do you see your spikes right after a deploy? If so, your assets may not be precompiled in that environment. You may even have both problems.

Rails Application - Using Cloudfront for asset delivery with Heroku

The situation
I couldn't get my vendor assets to precompile in heroku without specifying each individual file to precompile in config/initializers/assets so resorted to setting
config.assets.compile = true
Note: I didn't require vendor assets in application.js because I'm calling them on a per page basis when they are needed.
Anyhow I setup a Cloudfront account and now everything is working as it does in development. But on deploy to Heroku, there is a warning and a link that leads to a StackOverflow post, warning against setting config.assets.compile to true.
Compile Set to True in Production If you have enabled your application
to config.assets.compile = true in production, your application might
be very slow. This was best described in a stack overflow post:
When you have compile on, this is what happens: Every request for a
file in /assets is passed to Sprockets. On the first request for each
and every asset it is compiled and cached in whatever Rails is using
for cache (usually the filesystem). On subsequent requests Sprockets
receives the request and has to look up the fingerprinted filename,
check that the file (image) or files(css and js) that make up the
asset were not modified, and then if there is a cached version serve
that.
This setting is also known to cause other run-time instabilities and
is generally not recommended. Instead we recommend either precompiling
all of your assets on deploy (which is the default) or if that is not
possible compiling assets locally.
My question is, Since I'm now using Cloudfront, does that cover me from what they are warning about, slowness etc.?
Thanks in advance for any advice :)
Yes, you're likely covered. The request for an asset will hit CloudFront first. After the first request, it will be cached and shouldn't hit your server for compilation. Every time your assets change, however, they'll have to recompile, which is of course very slow.

Rails asset_host, cloudfront and heroku

I'm running a rails 4.0 app on heroku and for the life of me I can't get my asset urls using the host I've set in asset_host.
I believe my cloudfront setup is good because I can substitute in my cloudfront url for any of my asset urls and the file is picked up from heroku and cached on cloudfront.
So https://xxxxxxxxxxxx.cloudfront.net/assets/application-xxxxxxxx.js is caching https://myapp.com/assets/application-xxxxxxxxx.js correctly.
The issue seems to be my assets helper, such as javascript_include_tag, are never using the asset_host setting in staging.rb.
All I see when I load my page is all my js and css files being served from https://myapp.com/assets/
My staging setup looks like this:
# Full error reports are disabled and caching is turned on
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
# Disable Rails's static asset server (Apache or nginx will already do this)
config.serve_static_assets = true
# Compress JavaScripts and CSS
config.assets.compress = true
# Don't fallback to assets pipeline if a precompiled asset is missed
config.assets.compile = true
# Generate digests for assets URLs
config.assets.digest = true
#config.assets.digest = false
#config.assets.initialize_on_precompile = true
config.static_cache_control = "public, max-age=31536000"
# user Amazon Cloudfront for asset hosting
config.action_controller.asset_host = "https://xxxxxxxxxxxx.cloudfront.net"
Is there a magic combination of config settings that has somehow eluded me?
Ok, finally figured out what was going on - my app was using the rails_api gem, which removes a whole bunch of middleware from the standard rails stack.
Changing my application controller to class ApplicationController < ActionController::Base added back in the required middleware, and asset_host started working immediately. I'll investigate further to determine which middleware it is later and decide whether I want to go back to rails_api.
One more issue I then discovered was that rack-mini-profiler rewrites cache headers to always revalidate, thus negating most of the benefit of the cdn. I've now disabled it in staging and prod and my app is running a lot more snappily!

IE8 chokes on compressed CSS (Rails)

Like the title says, I'm having a problem with IE8 and compressed CSS. IE8 looks totally jacked up. (Using Rails 3.1 with asset pipeline)
At first I though it was the IE 4095 bug. It turns out I only have 1034 selectors.
In production, and also after running bundle exec rake assets precompile locally CSS began to break.
Out of curiosity, I decompressed the CSS Rails / Sprockets / Asset Pipeline spit out ..
IE didn't break on the un-compressed version.
Seems as though IE8 can't handle the giant compressed file.
I put a ticket in to see if there is an option to output both a compressed and uncompressed version, then conditionally load the uncompressed to IE.
In the meantime, I'm going to try to just turn off Rails compression for the moment.
config.assets.compile = false
// in development.rb
bundle exec rake assets precompile
// assets COMPILED anyway. agghhh!
Sort of out of ideas. Any suggestions welcome!
Thanks!
Edit
Based off this script, I started writing Middleware that serves uncompressed
CSS to IE8.
I've gotten pretty far, but noticed a lack of Ruby Gems that decompress CSS.
I use the sass-rails gem for CSS compression.
Then in production.rb:
config.assets.compile = false
config.assets.compress = true
config.sass.style = :compressed
config.assets.compile is not doing what you expect. This actually means on-the-fly compilation, not pre-compilation. config.assets.compress is what you are looking for.
I had the same issue. The only work around is to break out your compressed javascript into more than one file. I ended up breaking up my scripts into two different compressed files. This fixed the issue.
Hope that helps.

Cannot configure assets via pipeline on local production rails 3.1.3 server

This month, I upgraded from Rails 3.0 to Rails 3.1 - this week I tried to launch the server in production mode - today I have hit a wall !
I am unable to get my production environment server to serve up my public assets (JavaScript and CSS) via the asset pipeline, unless I set config.assets.compile = truein my environment.rb file, which for speed reasons I obviously don't want to do.
I have a large number of JS and CSS files, each of which tends to get used on one or two different pages. This means creating a single "manifest" file doesn't fit my usage, as each page wants something slightly different. I also expect some of the CSS won't sit together nicely. Therefore I have gone down the approach of "just get it working", looking to tidy up the large quantity of CSS / JS later.
Here is the production.rb file:
Implicit::Application.configure do
...
config.consider_all_requests_local = false
config.action_controller.perform_caching = true
# I set this to true, as I am testing this locally, just running a local Thin server
config.serve_static_assets = true
config.assets.compress = true
# Setting this to false removes the issue - but is SLOW
config.assets.compile = true
config.assets.digest = true
# This is overkill - but does get EVERYTHING precompiled for now
config.assets.precompile += %w( *.css *.js )
config.action_dispatch.x_sendfile_header = nil
...
end
This is quite a new area for me, and so I've spent much of today toggling these booleans and stop/starting the local Thin / Rails server to try them out. But the only value that's made a solid difference is the compile flag.
My application.rb file is pretty much standard, and has config.assets.enabled = true and config.assets.initialize_on_precompile = false in it, the latter from a heroku post (and a guess, again).
I have a fully populated public/assets directory, created with the bundle exec rake assets:precompile command, that takes about 20 mins to run on my oldish laptop (5 years), probably something to do with that "catch all" precompile regex, although with that line commented it still takes over 10 mins (!)
With the compile flag set to true, I can see copies of these assets getting created in my /tmp/cache directory - this is clearly the application creating it's own "compiled copy" of the assets.
With the compile flag set to false, I am confronted with the error message (in the logs, unless I set requests to local, then I see it on the rendered error page) of jquery.reveal isn't precompiled. However, when I go to http://localhost:3000/assets/jquery.reveal.js the javascript file is served up.
The line of my application layout causing this is:
<%= javascript_include_tag "application", "jquery.reveal" %>
I have tried changing that jquery.reveal to jquery.reveal.js with no change. Removing it fixes the index page, except that the jquery.reveal functionality is gone of course ! So clearly the application.js is being served up correctly. I just can't figure out why jquery.reveal isn't, as I can see the precompiled files in the public/assets directory.
This is an interesting issue, and I think there may be two bugs - the one you've linked and another: the file is being being compiled to the wrong name. It might be worth trying to generate a minimal test case that you can submit with a bug report.
The workaround for this - and I suspect that this is why few people seem to have the problem - is to use a secondary manifest (linking libraries only via a manifest seems to be an evolving best-practice).
Create one called home.js and require just that one file to it.
This isn't a bad approach overall. These extra manifests have to be added to the precompile array (see the guide), and allow multiple libraries to be shared over several pages or sections without having to link them each time.
Answering my own question here, but looks like it might be a bug in parsing assets with "periods" such as jquery.reveal
An issue report (https://github.com/rails/rails/issues/3398) reports this and highlights a commit (https://github.com/sstephenson/sprockets/commit/4ba5b32764a9073671df5e77355df6ed2bb3d3c9) which occurs just after Sprockets 2.0.3 - the default version that rails 3.1.3 relies upon. Upgrading Sprocket would therefore involve moving onto 3.2-stable rails - a bit bleeding edge for this newbie !
But the bug report does say this only occurs when config.assets.compile = true - and I did see whilst that was the case in my code that jquery.reveal was being dynamically compiled to jquery-8fu...8g.reveal.js (instead of jquery.reveal-8fu...8g.js).
So perhaps this ISN'T the answer. At least I hope it isn't. But will certainly continue to look at this period issue, as the "non-period" containing CSS / JS files are being served up just fine, as far as I can tell.

Resources