Skip to content

Instantly share code, notes, and snippets.

@HazelGrant
Last active August 29, 2015 14:10
Show Gist options
  • Save HazelGrant/b2686a149c793bea82a3 to your computer and use it in GitHub Desktop.
Save HazelGrant/b2686a149c793bea82a3 to your computer and use it in GitHub Desktop.
Javascript/asset pipeline problem with Confreaks.tv

Hello!

My problem is that Bootstrap's dropdown toggle menu has stopped working in the header of Confreaks.TV. I've built a lot of this project learning as I go, without a lot of familiarity with the tools I'm using. The asset pipeline has been particularly frustrating to me. Basically, everything is tangled and messy. I've learned a lot about it since starting the project, but I'm still stumbling around fairly blind. I can grant you access to the private bitbucket repo or provide more information if I haven't provided enough context for the problem here.

The Problem

To start, the dropdown toggle is used in the site's header:

- if user_signed_in?
  %li.dropdown
    = link_to '#', class: 'dropdown-toggle', 'data-toggle' => 'dropdown'  do
      = current_user.username
      %i.fa.fa-angle-down
    %ul.dropdown-menu
      %li
        ...

The dropdown will not toggle with the application.js set up as follows:

//= require jquery
//= require jquery_ujs
//= require bootstrap

...

//= require_tree .

However, if I move

//=require bootstrap

to the top of the file (so that it's above //=require jquery), the dropdown works perfectly. But doing this raises an error in the browser console:

Uncaught Error: Bootstrap's JavaScript requires jQuery

I know that Bootstrap needs jQuery loaded first in order for many of its functions to work. At the moment, there's nothing else I can find on the site which is broken by this error. It's a cause for concern, though, and I'd rather deal with it now than later.

Some solutions I've tried

  1. Removing duplicates of bootstrap.js

    I read that you only need one copy of bootstrap.js in an application and accidentally including it multiple times in the form of bootstrap.min.js and bootstrap.js can cause dropdown toggles to not work, so I initially removed bootstrap.js (leaving bootstrap.min.js) in application/vendor/template/etc. (where the code for our bootstrap template is located). This didn't solve the problem.

    I use the gem 'rails-assets-bootstraps', built from http://rails-assets.org, which makes bootstrap available without including any of the files within the application (except for calling them where appropriate in application.js and application.css (or application.css.scss in my case)). So I thought if I removed all bootstrap.js files from the application (including bootstrap.min.js files), this would get rid of any duplication and fix the issue. So I removed bootstrap.min.js from the template directory as well. Once again, it doesn't break anything, but it doesn't fix the dropdown toggle.

  2. Calling the dropdown via javascript in application.js

     $('.dropdown-toggle').dropdown()
    
  3. Clearing and precompiling the assets & restarting the server.

     rake assets:clobber; rake assets:precompile
     rake assets:clean; rake assets:precompile
    

    Note: rake assets:clobber, without precompiling the assets again, fixes the dropdown.

  4. This Stack Overflow question includes the above suggested solutions & several others, all of which I have tried (where applicable) http://stackoverflow.com/questions/10218587/twitter-bootstrap-drop-down-suddenly-not-working

Solution?

rake assets:clobber

(clearing out public/assets) works, while the public/assets folder is gone, but when I run rake assets:precompile again it stops working. Due to previous struggles with Heroku and the asset pipeline, precompiling my assets is the only way to get the confreaks.tv to deploy currently… I think the long road to solving this problem involves getting to the bottom of that problem. I don't necessarily need that solved this second, though it's something I intend to look at in the future.

Having narrowed the problem down to how the assets are getting precompiled, I'm now feeling like I've been banging my head against a brick wall for way too long, trying to solve a problem that needs a more experienced eye than mine.

@searls
Copy link

searls commented Nov 27, 2014

tl;dr My recommendation is to figure out why asset precompilation was failing on Heroku push and to stop committing your precompiled assets. That will probably resolve all the other issues. If you share access of the project with me I can take a stab at this for you.

Aside from that, I think I'm following along for the most part. Here's what I suspect (and if I'm not right I think I need to look at the project setup and play with it to debug):

  1. You were loading in the script twice—once from the bootstrap gem and once from the file being in vendor/assets/javascripts or app/assets/javascripts, which you fixed by removing the duplicates
  2. When you precompile and then run in development mode, there's a good chance that you're once again double-loading things locally. In general, I take care to always delete my public/assets directory (and not to commit it). The risk is that I'll forget and I'll have public/assets/application-SOMEHASHSIGNATURE.js present when I'm in development mode while also having sprockets in development mode. This may technically be supported, but it never works in practice and it will result in exactly the kind of situations you're describing.

If you run RAILS_ENV=production rails s locally while your precompiled assets are present, does everything work? I suspect they will. However, that's really no way to work, since it means the local server won't pick up any changes you make to the javascript unless you stop everything and re-precompile.

I tend not to use asset gems like rails-boostrap because it can obfuscate issues like this (whereas dropping files in vendor/assets/javascripts is obvious and straightforward).

@HazelGrant
Copy link
Author

The dropdown is still broken in production with public/assets included.

However, I just found that if I remove the reference to bootstrap in application.js the drop down works. So it is/was a case of duplication. Bootstrap.js gets included with the rails-assets gem and thus doesn't need to be included in application.js (at least I'm assuming this is the case). However at this point if I delete public/assets, the dropdown stops working again in development.

So rails-assets includes bootstrap.js when the assets are precompiled but doesn't make the file available in any other way. For now, I believe if I deploy without //= bootstrap.js in application.js then the dropdown will work in production.

That still doesn't fix the problem of needing to precompile assets in order to deploy, period. I worked with that problem for a few days awhile ago and was completely blocked - I would like to look at it again and attempt to debug and/or hear your thoughts on where I might have gone wrong (if it's even possible to suss that out at this point).

Update:

So, dropdown still does not work in local production or when pushed to Heroku.

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