雑多開発ブログ(仮)

RailsのbootstrapでUncaught TypeError: Cannot read property 'fn' of undefined at setTransitionEndSupport エラーが発生する 他。

ローカルで動くHTML,CSS,JavascriptRailsで動かそうとしたらJSが大量にエラーを吐いていました。ChromeのF12でConsleを確認すると f:id:lilacxi:20181124151114p:plain いろいろとエラーが出てますね....。でてきたエラーは

  • Uncaught TypeError: Cannot read property 'fn' of undefined at setTransitionEndSupport - bootstrap.min.js
  • Uncaught ReferenceError: jQuery is not defined - 他js

これらのエラーは同じ原因によって発生しているようです。

原因 jQueryが読み込まれる順番が遅い

RailsではAssetspipelineによってjsやcssが一つのファイルとして纏められます。

railsguides.jp

javascriptをまとめる順番はassets/javascript/application.jsで明示することができますが、デフォルトでは以下のようになっています。

// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's
// vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require_tree .

最後の//= require_tree .でassets/javascript内のjsをファイル名の順番で読み込んでいるようです。

cccabinet.jpn.org

ここを見るとbootstrapはjQueryとPopper.jsを先に読み込む必要があります。しかし//= require_tree .は名前順に読み込むので、名前がそのままだと

  1. bootstrap.js
  2. jQuery.js
  3. Popper.js

という順番で読み込まれてしまいます。どうやらこれのせいで「Uncaught TypeError: Cannot read property 'fn' of undefined at setTransitionEndSupport 」エラーは発生しているようです。以下のリンクでも同様のエラーが発生していたようです。

github.com

他のJSの「Uncaught ReferenceError: jQuery is not defined」エラーもjQueryを前提としているのにjQueryより先に読み込まれていることによるエラーのようです。

これを解消するにはapplication.jsで読み込む順番を明示してあげる必要があります。

解消方法

application.jsのrequire部分に以下のように書き加えます。

前略
//
//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require jquery-min
//= require popper.min
//= require_tree .

//= require_tree .の前に//= require jquery-min //= require popper.minと書くことによってjQuery,popper.jsを読み込んだ後に他のjsファイルを読み込んでくれます。このように他のjsの前提となっているファイルは//= require_tree .の前に書くようにすればいいですね。もしくは全てのjsを順番を明示して読み込むのもアリだと思います。

RailsでJavascriptのロード画面が終わらない

jQueryを使ってページを読み込んでいる間ロード画面を表示するようにしていましたが、何故か延々とロード画面が表示されてページが表示されません。

よくよく調べてみるとページ内のリンクから飛んだ場合は必ずロード画面で止まるのに対して、アドレスに直接飛んだりページ更新をした場合は問題なく表示されました。原因がわからずapplication.jsをいじくり回していたら原因がわかりました。

対処方法

application.jsの//= require turbolinksを削除する。

原因

turbolinks  こいつが原因でした。

kray.jp

Rails4以降ではデフォルトでGemfileに記載されているため、よく見てなかった自分のアプリにも入っていました。またapp/assets/javascript/application.jsでもデフォルトで読み込む設定をしています。

// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, or any plugin's
// vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require_tree .

下から二行目の//= require turbolinksで読み込んでますね。

自分の環境ではロード画面の表示をjQueryのreadyイベントで行っていたのですが、上記のリンクによると

turbolinksでページをロードすると、jQueryのreadyイベントが発火しません。

なんてこった。どうりで内部リンクから飛ぶと正常に表示できないわけです。

今回のアプリケーションでは他人が作ったJavascriptcssを動かそうとしていた為、ロード画面のコードはいじらずapplication.jsの//= require turbolinksを消すことによって問題を解消しました。

~/.bash_profileを弄ったらterminalの色が消えた

windows subsystem for linux なるものが出ていることに(今更)気がついたのでDebianを導入してみました。 ところが、rubyを入れるときにbash_profileを作成するとなぜかターミナルの色が消えてしまいました。

どうしたものかと思えばさくっと解決策が見つかりました。

stackoverflow.com

echo "source ~/.bashrc" >> ~/.bash_profile

bash_profile にこのように記述をすると、起動時に毎回"source ~/.bashrc"を読んでくれるそうです。 どうやらbash_profileがあると、bashrcは読みに行かなくなるようなので、bash_profile内でbashrcを読むように命令する必要があるようです。

Raspberry piでrails sを実行するとエラーがでる時の対処法

この対処法は原因解決の理由が不明の部分がある為、あくまで自分用の覚え書きです。

以下の環境でrails s -b 0.0.0.0を実行するとエラーが出て正常に動作しませんでした。

環境

rubyrailsの導入方法はこちらを参考にさせていただきました。

qiita.com

いろいろ弄っていたら問題なくrails sできるようになったので、自分用に残しておきます。

結論

Bus Errorの解消法

rails sの時にBus Errorが発生する場合、config/boot.rbを編集し require bootsnap/setup を削除するかコメントアウトすれば解消できます。

Segmentation faultの解消法

rails new xxx を実行する際に末尾に--skip-bundleを加えて実行します。このオプションをつけるとbundle installが自動で実行されません。 処理が終わったあとアプリケーションディレクトリにcdしbundle installを行います。
このようにrails newの時にbundle installをskipすると、何故かrails sを実行した際にSegmentation faultエラーで詰まらなくなります。

概要

rails new xxxをした後にrails s -b 0.0.0.0を実行した際、下記のエラー文が出ました。

$ rails s -b 0.0.0.0
/home/hoge/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/bootsnap-1.3.1/lib/bootsnap/compile_cache/iseq.rb:18: [BUG] Bus Error at 0x1a632ab
ruby 2.4.0p0 (2016-12-24 revision 57164) [armv7l-linux-eabihf]

~長文省略~

どうやらBus Errorとやらで正常に動作していないようです。
rails Raspberry pi Bus Error で検索した結果、以下のサイトがヒットしました。

romkey.com

どうやらbootsnapがRuby VMと相性が悪いそうです。この問題は少なくともRuby 2.4.1から2.5.1までに見られているそうです。
つまる所、bootsnapが有効だとBus Errorが出るようなので、config/boot.rbを編集しbootsnapを無効にしてあげれば解消できました。
ところがBus Errorを解消した後、rails sをすると下記のエラー文が出ました。

$ rails s -b 0.0.0.0
=> Booting Puma
=> Rails 5.2.1 application starting in development
=> Run `rails server -h` for more startup options
/home/hoge/.rbenv/versions/2.4.0/lib/ruby/gems/2.4.0/gems/rb-inotify-0.9.10/lib/rb-inotify/notifier.rb:54: [BUG] Segmentation fault at 0xe92d000e
ruby 2.4.0p0 (2016-12-24 revision 57164) [armv7l-linux-eabihf]

~長文省略~

なにやらrb-inotifyというgemでセグメンテーション違反が発生しているようです。セグメンテーション違反とはWikipediaによると

セグメンテーション違反(英語:segmentation fault)はソフトウェアの実行時に起きる特定のエラー条件である。segfault(セグフォールト)と略される場合がある。 セグメンテーション違反はアクセスが許可されていないメモリ上の位置、もしくは許可されていない方法(例えばリードオンリーの位置へ書き込みをしようとする、もしくはオペレーティングシステムの部分を上書きしようとする)でメモリ上の位置にアクセスしようとするときに起こる。
セグメンテーション違反 - Wikipedia

なるほど?正直な所、自分にはどうすれば解決するかわかりませんでした。しかし結論で述べたようにrails newを実行する際にbundle installをskipし、後ほどbundle installすることによってセグメンテーション違反を解消することはできました。なぜ解消できたか不明な為、あくまで自分用の一時的な対処法です。

Raspberry piのファイルをSambaで共有してWindows10から編集する

Apacheで表示するhtmlをメインPCから編集したかったのでやってみました。

自分用備忘録を含むためApacheをインストールする所から書くので、メインPCに共有したいフォルダがRaspberry piにある場合は2.以降を参照してください。

今回使用したバージョン

1. Apache2のインストールと設定

取り敢えずapt-getをupdate、upgradeしてからapache2をインストールします。

$ sudo apt-get update

$ sudo apt-get upgrade

$ sudo apt-get install apahce2

apache2でのデフォルトディレクトリは /var/wwwです。この中にhtmlファイルを置くと、ブラウザから表示することができます。

apache2のディレクトリを変更する場合は、指定したいディレクトリを記述した設定ファイルを登録する必要があります。 私はこちらのサイトを参考にさせていただきました。 g2-girichan.hatenablog.com

confファイルを弄り私は /home/public/www をディレクトリに設定しました。

今回はSambaで/home/publicを共有することによって、メインPCから/home/public/www内のhtmlを直接編集することができるようにします。

2. Sambaのインストールと設定

ラズパイにSambaをインストールすることで指定したフォルダを共有することができるようになります。なので取り敢えずSambaをインストールします。

$ sudo apt-get install samba

Sambaをインストールした後にやることは3つあります。こちらを参考に進めさせていただきました。

www.virment.com


Sambaにユーザーを登録する

Sambaには登録されたユーザーか、あるいはゲストとして接続する必要があります。今回はRaspberry piに専用のユーザーを用意してSambaに接続します。
まず新しくユーザーを作成します。このユーザーはSambaへの接続にしか使わないので、今回はhomeにディレクトリは作っていません。

$ sudo useradd hoge

このユーザーをpdbeditコマンドを使いSambaユーザーとして登録します。

$ pdbedit -a hoge

このコマンドを実行するとパスワードを入力するように求められます。このパスワードはSambaに接続する時にメインPCから入力するものです。

共有するフォルダのパーミッションを変更する

Linuxのフォルダやファイルにはパーミッションというものがあります。ファイルを閲覧したり編集する為の権限のことです。

メインPCから共有フォルダ内のファイルなどを編集する際には、Sambaに接続するユーザーと共有フォルダの権限が一致する必要があります。

自分のためにパーミッションがどういうものか覚え書きをするので興味のない方は ここ をクリックしてください。



mkdirで作ったディレクトリのパーミッションは親ディレクトリのパーミッションが操作ユーザーと異なる場合rootになるようです。例としてに /home/public/wwwのパーミッションを見てみましょう。パーミッションは ls -lで見ることができます。

:/home/public $ ls -l

drwxr-xr-x 2 root root ~省略~ www

これがなにを表しているかはこちらにとても丁寧に記載されていました。

qiita.com

こちらを参考にls -lによるwwwの結果を読み取ると

  • ディレクトリの所有者は読み取り書き込み実行の全てができる。
  • 所有グループとその他のユーザーは読み取りと実行しか行うことができない。
  • 所有者はroot、所有グループもrootである。

ということがわかります。つまりrootでないとディレクトリ内のファイルやフォルダを編集することができないということです。

したがって今回の場合では共有したいディレクトリのパーミッションをSambaユーザーにものにする必要があります。

ちなみにwwwディレクトリのパーミッションがrootに設定されたのはAというアカウントでrootパーミッションであるpublicディレクトリ下にmkdirしたからです。逆に/home/A/ など親ディレクトリのパーミッションと操作ユーザーが一致するディレクトリにmkdirすると、作られたディレクトリのパーミッションは操作ユーザーのものになるようです。



では共有するディレクトリをhogeで編集できるようにしましょう。パーミッションの所有者をhogeにしても良いですが、この先Sambaユーザーが増えるかもしれないことを考えてSambaユーザー全てが所属するグループ「groupS」を作ることにします。その後共有ディレクトリの所有グループをgroupSに設定します。

まず新しくグループを作り、そのグループにhogeを追加します。

$ groupadd groupS
$ gpasswd -a hoge groupS

今回共有したいディレクトリは /home/publicです。chgrpコマンドを用いてpublicの所有グループをgroupSに設定します。

$ chgrp groupS /home/public/

所有グループに書き込みを行う権限がないので権限を与えます。

$ chmod -R 775 /home/public/

/homeでls -lを行うとpublicに対してこのように表示されます。

drwxrwxr-x 2 www-data groupS ~省略~ public

このように出たら成功です。Sanmbaユーザーでログインし共有ディレクトリに対して書き込みを行うことができるようになっています。ちなみに775にしている理由はその他のユーザーでも実行できるようにしておかないとApacheが読み込めなくなるからです。

Sambaの設定をする

Sambaはインストールすると設定ファイルを /etc/samba/smb.conf として生成します。

共有するフォルダなどの設定はこのファイルを弄ることで設定することができます。

$ sudo vi /etc/samba/smb.conf

でsmb.confを開き、ファイルの末尾に以下の文章を追記します。

[public]
comment = apache directory
path = /home/public #"指定したいディレクトリ"
writable = yes
hosts allow = 192.168.xxx.

[public]は共有した時に表示する名称です。

commentは共有先一覧を詳細表示で見た時にコメントに表示される文章です。

pathは共有したいディレクトリです。私の場合はApacheディレクトリの一つ上のディレクトリを指定しています。

writableは共有するフォルダでの書き込みを許可します。これを記述しないとファイルが開けても書き込むことができません。read only = no と記述しても同様の効果を得ることができます。

host allowは接続できるIPアドレスを指定しています。ローカルネットワークのIPアドレスを指定することでLAN内からしか接続することができないように設定することができます。

これらの設定項目はこちらを参考にさせていただきました。

www.uetyi.com

設定ファイルに記述して保存した後にはsambaのサービスを以下のコマンドで再起動する必要があります。

$ sudo service smbd restart
$ sudo service nmbd restart

ここまで設定したらRaspberry pi側で行う操作は以上です。

3. Windows10での設定

さて、ここからは共有ディレクトリに接続するためにメインPCであるWindows10の設定を行っていきます。

ネットワークを開いてもRaspberry Piを見つけることができないと思います。これはWindows10があるアップデート以降SMB1をデフォルトでインストールしなくなったからです。詳しいことは本筋から外れるため記しませんが、とにかくSMB1を有効にしないとネットワークにSambaが表示されなくなっているようです。表示する方法があれば是非教えてください。

ネットワークで見つからないので直接ネットワークドライブとして割り振ることにします。

PCを右クリックして「ネットワークドライブの割り当て」を選択します。

f:id:lilacxi:20180814084940p:plain

割り当て画面で\\"Raspberry piIPアドレス"\public をフォルダーとして選択します。

f:id:lilacxi:20180814085123p:plain

完了を押しPCに出てきたpublicを表示しようとすると「ネットワーク資格情報の入力」というポップアップが表示されます。

f:id:lilacxi:20180814091039p:plain

ユーザー名に"hoge" パスワードにSambaにユーザー登録した時のパスワードを入力します。資格情報を記憶するにチェックを入れOKを押せば無事接続完了です。

4. おわりに

共有するフォルダのパーミッションあたりが詰まりやすいのではないかと個人的には思います。自分用メモとしての役割が大きいですが、参考になれば幸いです。