経緯
railsの勉強を始めて3週間。Udemyのコースを見ながら、簡単なブログ形式のサイトを(なんとか)作り、次はActionCableを用いたチャットアプリの作成することに。前述のUdemyのコースでは、Rails5環境で全て実装していたのですが、ほぼ写経になってしまうのが嫌だったので、無理矢理7で作ってみることにしました。その際、フロントエンド部分で採用されていたSemantic-UIで使われるjqueryの実装でハマりました。同じようなところではまっている方がいらっしゃるようだったので備忘録としてここに残します。
Semantic-UIは読み込めてるっぽいけど、dropdownが動かない...!
railsでsemantic-uiを使うには「semantic-ui-sass」というgemをインストールし、application.scssなどのSassファイルに、
@import 'semantic-ui'
と記述することで利用可能になります。これだけで、ERBファイルにsemanticのタグを追加していけばスタイルはちゃんと適用されます。ここまではRails5でも7でも同じです。問題はdropdownやaccordionなどのアニメーションにjqueryを用いている要素を機能させるためには当然jqueryが必要になるわけですが、この導入が5と7では(6とも)大きく違っていた、ということです。初心者の私はここで大躓きしました。。。
Rails7の情報少なすぎ問題
正直7でやろうとしたのをすでに後悔していましたが、負けたくなかった(誰に)ので踏ん張ってみることにしました。ですが7はリリースされてからまだ日が浅く、というか多分実務でもまだあまり利用されていない?ようで情報がヒットしません。ヒットするのは6の情報ばかり。ネットがダメならと思いkindleで7関連の書籍を検索するもこれもない。やはり7はまだ早いのかもしれないですね。特に私のような初心者には。辿り着いたのは公式ドキュメントでした
「公式ドキュメントを読め」
先人たちが百万回は言ったであろうこの言葉はやはり真理でした。
公式ドキュメント(参照後述)によると、rails7ではjqueryやsemantic-uiなどの外部モジュールの導入に、importmapという機能を使うのが推薦されています。
importmapの役割は、あくまでマッピングであり、実際のインポートは従来通り、application.jsで行います。importmapでは設定ファイルに設定を記述することで、CDN経由でnpmパッケージを使うためのマッピングをすることができます。
importmapの使い方
実際にimportmapの使い方を見ていきます。
ここでは、Semantic-UIの導入を例に取り上げます。
下準備
importmapはRails7環境にデフォルトで入っている、「importmap-rails」というgemで使えるようになります。つまり7環境では特に何もしなくてもimportmapが使えるようになっているはずです。以下がGemfileに記載されていることを確認してください。
gem 'importmap-rails'
これにより、プロジェクトディレクトリ下の、/configディレクトリ内に、importmap.rbというファイルが生成されます。importmapによる実際のマッピングはこちらのファイルに記述していきます。
また、views/layout/下のapplication.html.erbのheadタグ内に、以下の記述があることを確認してください。
<head>
//...略
<%= javascript_importmap_tags "application" %>
</head>
ここまではRails7環境であれば、rails new時に特に設定をしていなければ、デフォルトでこの状態になっているはずです。この状態になっていればimportmapを用いて、npmパッケージをプロジェクトに追加することができます。
jQueryとSemantic-UIの導入
ではimportmapを使ってSemantic-uiを導入していきます。
マッピング
pin "任意のパッケージ名", to: "ソース"
importmap.rbにこのように記述することでモジュール名とそのソースをマッピングすることができます。
これで、ちょうど、テーブルのキーとバリューような関係が構成されるので、インポートの際にモジュール名でソースを引っ張ってくることができるようになります。
ではまず、semantic-uiに必要なjqueryをマッピングします。
pin "jquery", to: "https://ga.jspm.io/npm:jquery@3.6.0/dist/jquery.js"
と直接追記するか、コンソール上で
$ ./bin/importmap pin jquery
を叩けば、CDNで対象のnpmパッケージが見つかれば、自動的にimportmap.rbに追記してくれます。
合わせて、Semantic-UIを追加します。以下をimportmap.rbに追記してください。
pin "semantic-ui", to: "https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.js"
importmapによるマッピングはこれで完了です。
インポート
続いて、importmapの記述からapplication.jsで、semantic-uiとjqueryをインポートします。
以下を記述してください。
import "semantic-ui"
import * as jquery from "jquery"
// または
import "jquery"
ダブルクォーテーションで囲われた文字列(パッケージ名)は、importmap.rbの、pinの直後に記載したパッケージ名と一致させてください。
そうすることで、importmap.rbに記載した通り、上記はそれぞれ内部的に
import "https://cdnjs.cloudflare.com/ajax/libs/semantic-ui/2.4.1/semantic.min.js"
import * as jquery from "https://ga.jspm.io/npm:jquery@3.6.0/dist/jquery.js"
import "https://ga.jspm.io/npm:jquery@3.6.0/dist/jquery.js"
に変換され読み込まれます。
以上がimportmapを用いた、Semantic-UIの導入になります。
私がハマったところ
補足として、application.jsで以下のように記述すると、
import jQuery from "jquery"
文法上は間違っていなさそうなのですが、
The requested module 'jquery' does not provide an export named 'default'
というエラーが出力されて、「'jquery'はデフォルトで何もexportしねえよ!」と怒られるのでご注意ください。(というかこの仕様の仕組みがまだ理解できていないのでどなたかわかる方いらっしゃいましたら、お教示いただけると幸いです。)
Rails7でSemantic-UIのdropdownを機能させる
Rails7ではturbo-railsというgemがこれまでのturbolinksを置き換える形で入っており、jqueryを正常に機能させるためには、turboの挙動を制限する必要があります。
dropdownを機能させるには、application.jsに以下を追記してください。
$(document).on('turbo:load', function () {
$('.ui.dropdown').dropdown();
})
以上で正常にRails7上でSemantic-UIのdropdownが使えると思います。
結論
ということで、ハマりました。やっぱり新しいもので開発するってだけでこんなにも大変なんですね。思い知らされました。
色々な書き方を試す中で試行錯誤していくんですね。それにしてもこれを解決するだけで丸一日費やしました。先が思いやられます。