質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.93%

Bootstrapのmodalが正常に動作しない Rails6 + webpacker環境 "modal is not a function..."

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 402

naokit-dev

score 415

環境

Ruby 2.7.1, Rails 6.0.3, PostgreSQL 11
webpacker 5.1.1
Bootstrap 4.5.0, jQuery 3.5.1 (gemを使用せずwebpackerにてインストール)
Docker上のローカル環境

Bootstrapのスタイルは正常に適応されている状態です

問題

BootstrapのModalが正常に動作しない
(CDNからBootstrapをインストールすると正常に動作する)

CDNインストールでお茶を濁しておりましたが、
プロダクション環境では問題ないものの、デプロイ環境ではjQueryがBootstrapよりも先に読み込まれていない旨のエラーが出ており、
根本解決が必要かと思い質問を挙げさせていただきました。

検証

プロダクション環境、modalの動作が期待される場面で
Chromeのコンソールで確認すると

Uncaught TypeError: $(...).modal is not a function...

そこで<head>タグ内に以下のように記述し、
CDNからインポートを試みるとmodalは正常に動作するようになります。
(jQueryとStylesheetのCDNインポートは不要でした)

  <head>
    ...
    <%= stylesheet_pack_tag "application", media: "all", "data-turbolinks-track": "reload" %>
    <%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track": "reload" %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
    <!-- font awesome -->
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.2.0/css/all.css"
      integrity="sha384-hWVjflwFxL6sNzntih27bfxkr27PmbbK/iSvJ+a4+0owXq79v+lsFkW54bOGbiDQ" crossorigin="anonymous">
    <!-- Bootstrap -->
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js"
      integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous">
    </script>
  </head>

このことから

  • ビューに記載されたスクリプトは適切
  • modalのclass, id記述も問題ない

かと考えています。

また上記<head>内で
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
よりも上の行でBootstrapをCDNからのインポートすると、
同様にChromeのコンソールにて、jQueryに依存しているから先にインストールしてくれとのエラーが生じます

このことからwebpackerでのjQueryのインストールまではうまくいっており

  • Bootstrapのインストールがうまく行ってない
  • jQuery > Bootstrapの順で呼び出されていない

といった原因なのかと推察しているのですが、
これ以上検証、解決のすべが思い浮かばず質問させていただきました。

長文、お手数ですが後学のためアドバイスをお願いいたします。

ソース

config/webpack/environment.js

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

const webpack = require('webpack')

environment.plugins.prepend('Provide',
  new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    Popper: ['popper.js', 'default']
  })
)

module.exports = environment

app/javascript/packs/application.js

// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.

require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
require("@fortawesome/fontawesome-free")

import 'bootstrap'
import 'bootstrap/dist/js/bootstrap';
import './bootstrap_custom.js'
import '../stylesheets/application'



// Uncomment to copy all static images under ../images to the output folder and reference
// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)
// or the `imagePath` JavaScript helper below.
//
// const images = require.context('../images', true)
// const imagePath = (name) => images(name, true)

importの内容は重複していますが、
それぞれ個別に試してもエラーは解消されませんでした

また、以下のサイトを参考に、
import 'bootstrap/js/dist/modalを含むbootstrap_custom.jsを作成し
Bootstrapのjavascriptを明示的にimportしてみたのですが
これもうまくいかず

How to install bootstrap 4.3 on a Rails 6 app using Webpack | by Guilherme Pejon | Medium

app/javascript/packs/bootstrap_custom.js

import 'bootstrap/js/dist/alert'
import 'bootstrap/js/dist/button'
import 'bootstrap/js/dist/carousel'
import 'bootstrap/js/dist/collapse'
import 'bootstrap/js/dist/dropdown'
import 'bootstrap/js/dist/index'
import 'bootstrap/js/dist/modal'
import 'bootstrap/js/dist/popover'
import 'bootstrap/js/dist/scrollspy'
import 'bootstrap/js/dist/tab'
import 'bootstrap/js/dist/toast'
import 'bootstrap/js/dist/tooltip'
import 'bootstrap/js/dist/util'

 package.json

{
  "name": "myapp",
  "private": true,
  "dependencies": {
    "@fortawesome/fontawesome-free": "^5.13.1",
    "@rails/actioncable": "^6.0.0",
    "@rails/activestorage": "^6.0.0",
    "@rails/ujs": "^6.0.0",
    "@rails/webpacker": "5.1.1",
    "bootstrap": "4.5.0",
    "clipboard": "^2.0.6",
    "jquery": "^3.5.1",
    "popper.js": "^1.16.1",
    "turbolinks": "^5.2.0"
  },
  "version": "0.1.0",
  "devDependencies": {
    "webpack-dev-server": "^3.11.0"
  }
}

ビュー(.erb)

<script>
  $(window).on('load', function () {
    $('#modal_initial').modal();
  });
</script>

<div class="modal fade" id="modal_initial" tabindex="-1" role="dialog" aria-labelledby="modal_initialCenterTitle"
  aria-hidden="true" data-backdrop="static">
  ...
</div>

$('#modal_initial').modal();の部分を$('#modal_initial').show();$('#modal_initial.modal').show();とするとよいなどのアドバイスも海外サイトで見られましたが、いずれも駄目でした

追記

デプロイ環境でのみ、jQueryがないと言われるエラーについては
以下のように変更することで解消しました

config/webpack/environment.js

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

const webpack = require('webpack')

#以下'jquery'から'jquery/src/jquery'に変更
environment.plugins.prepend('Provide',
  new webpack.ProvidePlugin({
    $: 'jquery/src/jquery',
    jQuery: 'jquery/src/jquery',
    Popper: ['popper.js', 'default']
  })
)

module.exports = environment

現状の問題点は

  • webpackerで管理しているBootstrapのスタイルは適応されるが、特定のjavascriptが動かない
  • <head>内でCDNからBootstrapをインストールすると、前述のjavascriptが動く

対症的解決法はあるのですが、後学のため根本解決のためのアドバイスを引き続きお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

jQuery → Bootstrap → jQueryとjQueryが2回読み込まれBootstrapのメソッドがキャンセルされている可能性が高いかと思います。

なので、まずは該当ページで検証ツールを利用して<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>以外で、jQueryを読み込んでいないか確認することからはじめると切り分けがしやすいかと思います。


追記:解決方法はわかったのですが、なぜそうなるのかがわかりません。おわかりになる方がいらっしゃればコメントなどで教えていただけると助かります。

前提:
jQueryを2回読み込んでいない。

解決方法:
・erbに直接記載せず、application.jsなどに記載してjavascript_pack_tagから読み込む
・もしturbolinksを利用しているのならaddEventListenerを追加

//application.js

require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
require("@fortawesome/fontawesome-free")

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

document.addEventListener("turbolinks:load", function(){
    $(window).on('load', function () {
        $('#modal_initial').modal();
    });
})

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/29 17:15 編集

    こちらで新しいプロジェクトを作って確認してみました。

    Bootstrap、jQuery導入
    Qiita: https://qiita.com/shungo_m/items/53bcae18a740495d1eb3

    Application.jsに下記コードを追加
    window.jQuery = window.$ = require('jquery')
    上記でmodalのエラー(Uncaught TypeError: $(...).modal is not a function...)が消えました。

    rails g scaffold test name:textでtestページを作成
    testのindex.html.erbにbootstrap公式のモーダルコード(LiveDemo)をコピペ
    https://getbootstrap.jp/docs/4.2/components/modal/

    Turbolinksはひとまずおいて、下記コードを追加
    <script>
    $(window).on('load', function () {
    $('#exampleModal').modal('show');
    });
    </script>

    ページを立ち上げるとエラーもなく、モーダルが表示された状態になります。
    一度テストアプリで動作確認してから、現状のコードを確認すると良いと思います

    キャンセル

  • 2020/07/29 23:31 編集

    no1knowsさん

    動作確認できました
    解決までフォローいただきありがとうございました。

    おかげさまで新しい学びがあり、スッキリいたしました。
    また機会があればよろしくお願いいたします。

    キャンセル

  • 2020/07/30 01:18

    naoki_tさん、拙い解答でお手数をおかけしました。
    僕も勉強になりました。ありがとうございます!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.93%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る