10

I am a new to rails and struggling to get Jquery and Bootstrap to work with Rails 6. I think it has something to do with switching the app from rails 5 to rails 6 and using webpacker to load Jquery rather than loading it as a gem. I have gone through the instructions for this however it still doesn't seem to work properly. Someone helped me with a more specific problem and got me to paste this into the view which then seemed to make it work:

<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>

However, this feels like a workaround and I want Jquery available in all views. Below is a copy of /javascript/packs/application.js :

require("jquery")
require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
require("bootstrap/dist/js/bootstrap")

import '../stylesheets/application'
import './bootstrap_custom.js'


//= require jquery3
//= require popper
//= require bootstrap-sprockets

and /config/webpack/environment.js:

const { environment } = require('@rails/webpacker')

const webpack = require('webpack')
environment.plugins.prepend('Provide',
  new webpack.ProvidePlugin({
    $: 'jquery/src/jquery',
    jQuery: 'jquery/src/jquery'
  })
)

module.exports = environment

I don't get the difference between Require("...") and //= require ...? is the //= a legacy notation that should be converted to Require("...")?

Also do I need both require("jquery") and //= require jquery3? I assume not. If so which one should I delete?

In /apps/views/layouts/Application.html.erb I have the following contained within the header:

<%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
Tomas
  • 318
  • 3
  • 11

2 Answers2

28

I struggled with this for days, so hopefully my experience will help you :)

First of all, you will be loading jQuery and Bootstrap as a webpack module, so you don't need any of this:

<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>

Instead, you want to install the modules using yarn on your prompt:

$ yarn add jquery bootstrap

After that, you should import jQuery into your project. The safest way to do it is editing your /config/webpack/environment.js, much in the way you did:

...
environment.plugins.append('Provide',
  new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery'
  })
...

Now, since you're importing jQuery as a webpack global plugin (that is, available throughout all your views, and even from other modules), then you should not import it again in your app/javascript/packs/application.js, as this is a known cause for unexpected behavior. In that file you do want, however, to import Bootstrap. So it should look like this:

# app/javascript/packs/application.js

import 'bootstrap';
import '../stylesheets/application'

require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")

Note that I'm using the import 'module' syntax, which is preferred over the older require("") syntax. And you definitely don't want to use any of these:

//= require jquery3
//= require popper
//= require bootstrap-sprockets

They're Sprockets (asset pipeline) directives with no use in Webpack-land.

So, by now you have both jQuery and Bootstrap js imported into your project, but you're still missing Bootstrap stylesheet. In order to import it, just include this in your application.scss (which I assume you're using given you're importing it with import '../stylesheets/application'):

# application.scss

@import "~bootstrap/scss/bootstrap";

And there you are, jQuery and Bootstrap imported into your project. Hope it helps! If you're new to Webpack (as I am) you will encounter lots of obstacles before you can fully use it, since there are a lot of differences with the asset pipeline. After several days (if not weeks) of research I've managed to deal with most of them, so feel free to look into my question history to see if you find some useful answers.

Additional info:

  1. You didn't specify it, but if you're going to use all of Bootstrap's js functions, you'll also need Popper.js in your project. In order to install just run $ yarn add popper.js in your command line, and edit your /config/webpack/environment.js so it looks like this:
environment.plugins.append('Provide',
  new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    Popper: ['popper.js', 'default']
  })
)
  1. Lastly, I tried to answer your question in the most concise way I could, but if you're still struggling, you may want to check some more step-by-step tutorials, like this: https://medium.com/@adrian_teh/ruby-on-rails-6-with-webpacker-and-bootstrap-step-by-step-guide-41b52ef4081f. Also, I've put together a barebones Rails 6 core app with jQuery, Bootstrap and popper.js installed, so feel free to clone into the repo, here: https://github.com/Dijkie85/rails6core.git.

Good luck!

Dijkie85
  • 1,036
  • 8
  • 21
  • Thank you so much this is just the level of info I am looking for. I will try tonight and let you know how I get on. – Tomas Nov 11 '19 at 09:37
  • Your answer was very comprehensive and easy to follow, however, this didn't seem to work. The functionality where it breaks is in calling a bootstrap modal. The modal loads and the action is executed but I can't get the modal to close without adding the three lines of – Tomas Nov 11 '19 at 11:46
  • So I can repeat the issue I am having by swapping the order of ` – Tomas Nov 11 '19 at 13:11
  • Interestingly the answer here helped - [link](https://stackoverflow.com/questions/58195417/bootstrap-js-functions-not-loading-in-rails-6-webpacker). As I am not quite sure what this is doing I am not sure if this is the best solution or a workaround... Any thoughts much appreciated... – Tomas Nov 11 '19 at 13:31
  • I'm glad you made it work! I checked the link you provided, and indeed that's how I first managed to get jQuery to work in a project. However, maybe --like me-- you'll find out later that, with that method, you won't be able to call jQuery from additional plugins you may want to use in the future, so it's only a temporary solution. Should that happen, I encourage you to call jQuery from `/config/webpack/environment.js`, which exposes jQuery to every part of your project. Make sure you're using the syntax I provided (`$: 'jquery', jQuery: 'jquery'`), and not the one you first posted. – Dijkie85 Nov 11 '19 at 14:07
  • Thanks once again for your excellent help on this... I had left in the lines `const { environment } = require('@rails/webpacker')` and `module.exports = environment` in the environment.js. When I took these out it then worked... Do you know what these do and whether I need them or are they a legacy from shifting from rails 5? – Tomas Nov 11 '19 at 14:27
  • You definitely need those lines in order for webpack to actually include your global plugins. I didn't mean for you to take those out; I just mentioned what needs to be inside those declarations. If you took them out, and your jQuery is still working, it's very likely you are indeed importing/requiring the library multiple times by different means, which might be what is actually causing your issues. By the way, if you found this answered your original question (which was not directly related to modals), I'd appreciate you marked it as answered, in case it helps others :) – Dijkie85 Nov 11 '19 at 14:39
  • So now I am totally confused. I don't think it had worked after all - I think it was just that somehow `import JQuery from 'jquery'; window.$ = window.JQuery = JQuery;` was still having an effect after it was deleted... Any further thoughts... I now have enviroment.js back to how you suggested but with the bits top and bottom like my original post... – Tomas Nov 11 '19 at 15:20
  • You might still be having conflicting jQuery imports. I've been there, it's frustrating. Since you mentioned you're migrating from Rails 5, I'd check if there are any remaining js files in your /app/assets/javascripts or maybe in your vendor directory. Other than that, my approach would be to try to revert to an as much of a clean slate as you can. I don't know how big your app is now, but if it's not too much, you may consider going for a freshly created Rails 6 project, install jQuery, Bootstrap and Popper, test them, and then add your Rails 5 files, watching out for what breaks your js. – Dijkie85 Nov 11 '19 at 16:32
  • This is a great post. What is the purpose of the tilda in ```@import "~bootstrap/scss/bootstrap";``` – Obromios Jan 02 '20 at 22:57
  • Thank-you so much for this. I spent a whole day trying to solve it myself. – t56k Jan 09 '20 at 02:07
  • Under the Additional Info section, it talks about adding popper.js using yarn. Isn't that redundant? Doesn't bootstrap already include popper.js? You just need to enable it. How does one do that with webpacker? – Jared Jul 09 '20 at 22:21
  • In case anyone comes across this page troubleshooting Jquery, as I have. Popper installation syntax has changed slightly. It's now `yarn add @popperjs/core` – Greg Jul 19 '21 at 20:39
0

I use in Rails 6:

#/Gemfile
gem "bootstrap", "~> 5.1"
gem "jquery-rails", "~> 4.4"

#/app/javascript/packs/application.js
...
import 'bootstrap';

and

#/config/webpack/environment.js
const { environment } = require('@rails/webpacker')

const webpack = require("webpack")
environment.plugins.append("Provide", new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    'window.jQuery': 'jquery',
    Popper: ['popper.js', 'default']
}))

module.exports = environment
FVVID
  • 155
  • 1
  • 9