Static files not found after Rails app deployed to heroku - ruby-on-rails

I'm fairly new to the whole asset pipeline concept, I put the third party js file (as well as the css and image files) in the vendor/assets folder, allow me to give a quick example how I did it:
where the file is stored:
vendor/assets/javascript/plugins/isotope/isotope.pkgd.min.js
how it's referenced in the application.js:
//= require plugins/isotope/isotope.pkgd.min
and how it's referenced in the index.html.erb
<script src="/assets/plugins/isotope/isotope.pkgd.min.js"></script>
it works just fine locally, but after I deployed the app onto heroku, I got http://myapp.herokuapp.com/assets/plugins/isotope/isotope.pkgd.min.js not found error, without it, my app does not work...I kinda know part of the asset pipeline's job is to compress all the js files (the ones referenced in the application.js) into one single js file, does not mean I will need to refer isotope.pkgd.min.js differently in my html.erb?

There are several steps in debugging an asset pipeline problem. You didn't mention you'd done an asset pre-compilation before deploy. Heroku does not compile assets upon deploy automatically. Here's their text on the matter
If a public/assets/manifest.yml is detected in your app, Heroku will assume you are handling asset compilation yourself and will not attempt to compile your assets. Rails 4 uses a file called public/assets/manifest-.json instead. On both versions you can generate this file by running $ rake assets:precompile locally and checking the resultant files into Git.
https://devcenter.heroku.com/articles/rails-asset-pipeline
A simple test would be to precompile your assets (and git checkin, if you're using git push Heroku) before Heroku deploy and see if that doesn't resolve the issue.
On your dev platform:
bundle rake exec assets:precompile RAILS_ENV=production

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.

Parallax.js images render locally but not in production on Heroku

Disambiguation: There are two popular plugins called "parallax.js". I'm referring to this one.
In development, parallaxed and non-parallaxed images work perfectly in my ERB template. But in production (on Heroku), only the non-parallaxed images are rendering. I currently suspect my problem is with the Rails asset pipeline, but the recommended fixes haven't worked (see below).
The parallax.js docs suggest the following usage:
<div class="parallax-window" data-parallax="scroll" data-image-src="/path/to/image.jpg"></div>
But in order to use the asset pipeline, I've changed it to:
<div class="parallax-window" data-parallax="scroll" data-image-src="<%= image_url('image_file.jpeg') %>"></div>
(In addition to image_url, I've also tried image_tag and image_path.)
As mentioned, this all works just fine on my local machine.
But in production, the Chrome browser console logs errors for the missing images:
Failed to load resource: the server responded with a status of 404 (Not Found)
So I went down the rabbit hole:
Other SO pages (ie: here and here) suggest doing variations of rake assets:precompile RAILS_ENV=production or heroku run rake assets:precompile.
The latter command spends several minutes compiling unrelated css & js assets, and does not resolve the problem. The former command yields the following error:
Devise.secret_key was not set. Please add the following to your Devise initializer:
config.secret_key = (... and so on)
Using the heroku console I ensured proper values ARE present for ENV['SECRET_KEY'] and ENV['SECRET_KEY_BASE'].
In my devise.rb, I have:
config.secret_key = ENV['SECRET_KEY_BASE'] if Rails.env == 'production'
In production.rb I have:
config.serve_static_assets = true
config.assets.compile = true
config.assets.digest = true
This might be more info than necessary but I've included this since it all seems related.
Thank you.
Path used from Server to run the search
Your server does not find the file with the path your are giving him so please let's tell us where you are searching by with the console in both production and development type
Rails.application.config.assets.paths
Then evaluate any difference in those paths, because that is where the server is going to search for your asset
The file does not exist in production
If you set in development this parameter to false, it may also not work in development, demonstrating that the server is not finding the image also in that environment and is falling back to the file in app/assets
config.assets.unknown_asset_fallback = false
I wonder is the file present in your git repository? Because you are uploading to production through git, so you can check the file in your git repository under public/assets then you can go to your website, for example https://sprachspiel.xyz has an image
<img class="image_inverted" src="/assets/building-14c0a7cb155ad93ffbad41ab5ecb491691f2fc34684c7aa5735fedc659f99f76.svg" alt="Building">
and I can display the asset with the following path:
https://sprachspiel.xyz/assets/building-14c0a7cb155ad93ffbad41ab5ecb491691f2fc34684c7aa5735fedc659f99f76.svg
if you can not find the fingerprinted file in your git repository or you can not display it on your server/domain, it mean that the development server is just using the one in the app/assets folder and the file has not been precompiled/fingerprinted
so you need to make sure when you precompile development
rails assets:precompile
that you include those fingerprinted files in your git repository
git add .
then you need to check the files added
git status
should show in green the new precompiled files, so it will include some application-fingerprint.js .scss and also some images
then you need to commit
git commit -m 'assets precompile'
and push to production git push heroku master
Now on your heroku host you have exactly the same files from your git repository, you should check the heroku log in details and seeing what file are being uploaded, then you can go on your app domain and should be able to display all the files if you go at for example
https://sprachspiel.xyz/assets/application-461aa436b906133a708293d3f509c1908b34cf5b3d06c38332fcd7a5d75648a9.js
The problem of this is that as you can see from my git repository
https://github.com/fabriziobertoglio1987/sprachspiel/tree/master/public/assets
I have many application.js and scss, and same version of the same images with different fingerprints. That is why sometimes they tell you to delete the folder with rm -r public/assets, git add ., git commit -m 'deleted assets', then push to both github and heroku
Because it is confusing to have some many versions of the same file with different fingerprints, because heroku will only upload 1 file for application.js, scss and each image based on the settings included in the sprockets-manifest-fingerprint.json
which includes the fingerprint name of every file
{"files":{"anvil-24236-40f6914d480cedd181af319818100046542752b1af2618a9540560b9fe17441f.svg":{"logical_path":"anvil-24236.svg","mtime":"2017-06-19T00:05:49+07:00","size":3886,"digest":"40f6914d480cedd181af319818100046542752b1af2618a9540560b9fe17441f","integrity":"sha256-QPaRTUgM7dGBrzGYGBAARlQnUrGvJhipVAVguf4XRB8="},"anvil-4e059374f73b4972cad762b9ab5326dfce178997ad7dc902e5fd50c0db019c3d.svg":...}
https://github.com/fabriziobertoglio1987/sprachspiel/blob/master/public/assets/.sprockets-manifest-b19e945ef55d302416370238b2625751.json

What is the difference between shared/public/assets on production server and pre-compiled assets on rails public/assets on source code?

I pre-compiled my assets i.e CSS,javascript and fonts files in order to reduce the file size. Using RAILS_ENV=production rake assets:precompile.
I already have compressed assets on the server in the following path:
shared/public/assets
But anyway I went ahead and pre-compiled them again on my local and they got generated inside public/assets folder. I noticed that the compressed files are exactly as same as the ones on server shared/public/assets. But the tester in my team is been testing it on some online tools. And they all say "Your java script files need to be minified." So, would this "minifying" issue be solved if I push these locally pre-compiled assets to production source code?
You should not push locally pre-compiled assets to production source code, no.
Your build process should include precompiling assets for production during a deploy. If you're using Rails 5 then that is already turned on by default. As long as the production environment has a proper environment variable (again, by default, the environment variable 'production' takes care of all these things), the assets will be precompiled.
You say that your compressed files, after running rake assets:precompile, are exactly the same as the ones on the server. That means your javascript should have and should be minified and uglified (again, default for Rails 5). To confirm that's the case, open dev tools in chrome, hard-reload (ctrl+shift+r) and check with JS files are being loaded under "network" tab. If the asset pipeline was used as it should be, you should only see minified and uglified js files here. If you open them up, they should already be minified and uglified. If that's not the case then either the asset pipeline wasn't used for fetching the JS files or your build process has been changed.
If most of these JS files are minified and uglified with - check those which aren't. Is some library being added outside of asset pipeline? Are those files minified?
If all of your JS files are actually minified, then tell your tester to use a different tool ;)

How to deploy Rails 4 with Capistrano 2 and precompile assets locally

Recently I upgraded an application from Rails 3 to Rails 4. In the deploy scripts I precompile the assets locally and then rsync them up to the server(s). In Rails 4 the asset pipeline now produces manifest- < random > .json instead of a manifest.yml. Since the manifest files are named differently, this adds multiple manifest.json files to the shared assets directory. The application then picks up the wrong manifest file, and serves old assets.
I have read about various issues related to this in some github pull request threads:
https://github.com/capistrano/capistrano/pull/412
https://github.com/capistrano/capistrano/issues/210
https://github.com/capistrano/capistrano/pull/281
My options seem to be:
Don't share the asset directory.
This would break old clients asking for old resources.
Switch to compiling assets on the servers.
This would add complexity to the server.
Move the manifest file outside of the shared asset directory.
I have since learned that this option was removed in Rails 4.
Are there other solutions to this problem?
I found the best answer after looking at the standard capistrano rails asset precompile task. I added a command to the local precompile task that moves the old asset manifest to the current release as asset_manifest.json. This leaves only one manifest when the new one is uploaded.
run "mv -- #{shared_manifest_path.shellescape} #{current_path.to_s.shellescape}/assets_manifest#{File.extname(shared_manifest_path)}".compact
Moving the manifest-.json to the current_dir as asset_manifest.json allows capistrano to restore the correct manifest file on rollback.

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