This post was written by Flatiron student Becca Shapiro and originally appeared on her blog “<3: A Coding Blog“. Check it out to learn more about Ruby and Becca's journey to becoming a developer at the Flatiron School. Want to join Becca and hundreds of other students who have changed their career through code? Check out the Flatiron School's upcoming courses near you.
READ THIS POST IF: you are deploying an app to Heroku and the build fails while compiling assets.
Scenario: I'm working on an app that is styled using a theme from a vendor. I've copied the CSS files I need into vendor/assets/stylesheets and the javascripts into vendor/assets/javascripts, without any nesting. All files seem to be properly required in my app; my manifests require the vendor/assets trees and the styling and behavior in my app are as I want them to be. It comes time to push up to Heroku.
git push heroku master
She starts writing temp files, ok good… she runs rake assets:precompile
, it's looking normal… and then precompiling assets fails. What gives?
All the things I tried: (skip to the fix)
Precompiling Assets
It seems reasonable to try to precompile assets before pushing up to Heroku and then running the build again. So I run rake assets:precompile locally and it passes without fail. I push up to Heroku, and the build works! But I notice that my javascripts are broken, both locally and remotely. There's a sidebar that should expand and collapse upon click of the menu icon, and it isn't working. Huh.
Mixed Dependencies
So I look into my javascripts manifest and I think jquery might be required twice. It feels wrong, but I remove //require jquery and //require jquery_ujs. And javascripts go back to normal! Ok, cool. I continue business as usual. I decide to work on my login page. I click sign out and… what? Why am I served a rails error? It seems as though clicking the link that directs to users/sign_out is trying to take me to the users#show route, users/:id, because it thinks “sign_out” is a user_id. Devise was the first feature I implemented, over a week ago, and it's worked up til now. Weird. I troubleshoot this as best I know.
Route configuration
I change the order of the “devise_for” and “resources :users” in routes.rb. That doesn't do it. I remove “resources :users” completely. No dice. The sign out route is inherited via Devise as sessions/users/sign_out, so it's tucked away in the Devise gem within the sessions controller and isn't actually present in my project. But I can run
rails generate devise:controllers users
to generate this controller (and all devise controllers). I explicitly set
devise_for :users, controllers: { sessions: “users/sessions” }
hoping that by explicitly telling my routes.rb file where the sessions routes lives, it will no longer confuse the sign out and show routes. This doesn't do anything at all. I revert.
Asset loading
There's an entypo icon inside of my Sign Out link. Maybe having an asset inside of that link is breaking the link action? I remove it. No change. Revert.
Baseline compatibility: Does Devise play nice with Heroku?
How are my assets, devise, and heroku even related? Well, I start researching Devise and Heroku. Many sources confirm that sometimes compiling assets during a heroku push will break as a result of using Devise, but upon further research, this issue is specific to rails 3 and produces an error message dissimilar to that I was getting. So I ruled out Devise as the cause of the Heroku compile issue, and deduced that //require jquery
and //require jquery_ujs
had to be put back in.
Application configuration
I start vigorously searching stackoverflow. I add <%= javascript_include_tag :defaults %>
to application.html.erb. No change.
Javascript Manifest File (mounting order)
At this point, it seems like I need to diagnose why precompiling assets is break my javascripts in the first place. Are my scripts required in an incorrect order in the manifest file? I use rake assets:clobber to remove the precompiled assets I had just generated (which deletes the public/assets folder). I search the theme FAQs on the vendor site, but although the help topics are fairly thorough I find nothing referencing the mounting order of the javascript files. I un-require the vendor tree and look back into my theme and decide to manually list out each vendor javascript that I need, in the exact same order as the theme's example files. Re-precompile. No change.
CSS
I need to look at this from a new angle. If precompiling is working locally, albeit breaking my javascript, why does compiling break in Heroku push? I look back at the error.
rake aborted! Invalid CSS after
….. Wait, invalid CSS? What is that about? When I precompile, only the javascript is broken.
THE FIX!!!!
I grab a brilliant Flatiron instuctor who suggests the issue might have something to do with my manifest file being a SASS document while the rest of my stylesheets are a combination of CSS and SASS. I deduce it might be a good idea to standardize to either all SASS or all CSS. I'm not even using any SASS, so I change all of the .scss file extentions to .css, including the manifest file, remove 'gem SASS-RAILS
' from my Gemfile, bundle, commit, and push. It goes through. Heart racing. Open the heroku app. Styling is all in place. Sign in. Click the sidebar, it expands and collapses. Sign out.
TA DA!!! Oh my god. I can't believe I have spent 8 hours on this issue, and it was CSS the whole time – it had nothing to do with JQuery, or Devise, WHAT A RABBIT HOLE THAT WAS.
Moral of the story: If you try to push up to Heroku and your build is aborted in the middle of compiling assets, and you see an “invalid CSS” error message, check your file extensions FIRST.
Your issue is unlikely to be due to any of the following:
-
Devise (specifically, the order of your routes in routes.rb probably doesn't matter, and whether your controllers are tucked into Devise or present in your app file tree shouldn't either.)
-
Icons included in the display value of links
-
The order of your files in the javascript manifest
-
The presence of
//require jquery
and//require jquery_ujs
in the javascript manifest. READ: DO NOT REMOVE THESE. -
Javascripts included manually in the head of application.html.erb
-
The presence of old compiled assets
By the way, I couldn't find this information anywhere on stackoverflow. Watch me spread the gospel of this fix all over the internet. Needless to say I'll be making a sacrifice to the Heroku gods tonight. Godspeed, dear Heroku users.