はじめに
以前書いた記事の関連。事象としては、bundle updateしたらPassengerエラー発生し、Redmineが起動できなくなった、というものですが、その後の追跡調査によってどういう場合に発生するのかわかりましたのでまとめておきます。
原因
調査の結果、Nokogiri 1.11ではHTMLというクラスがNokogiri 1.12ではHTML4というクラスに名称変更されていることが判明。ちなみにLoofahは1.20までHTMLで1.21以降HTML4になっている。
RedmineとRubyのバージョンの組み合わせによってはNokogiri 1.11以前が選択される場合がある一方、Loofahのバージョンは指定されておらず、最新バージョンが選択される。
つまり、RedmineのGemfileでNokogiri 1.11以前が選択される場合は、クラス名変更の整合が合わず問題が発生する。この問題は、loofah1.21がリリースされた2023/5/10以降に発生することになる。
事象発生のメカニズム
- Gemfileにおける'~>'の意味は以下となっている
指定されたバージョンのメジャーバージョン、マイナーバージョンは指定したバージョンと同じであり、パッチバージョンは最新のものが選ばれる。 - Gemfileで書かれている最新のNokogiriが選ばれるわけではない。
例えば、'~> 1.10.10'
と書かれていた場合、1.10系の最新版が選ばれ、1.11以上は選ばれない。 - RedmineのGemfileでは、loofahのバージョンは指定されていない
loofahは必要に応じて最新版が読み込まれる。loofah2.21.0以降ではHTML4が使用されている。
- つまり、Gemfileの記述でNokogiri1.11が読み込まれるような環境では、loofahとバージョンが合わないためエラーが発生する。
- この問題は、loofah2.21.0がリリースされた2023/5/10以降、Nokogiri1.10より前のNokogiriを読み込むようなGemfileになっている場合に発生する。
対策
Nokogiri 1.11が選択される環境では、Gemfile.localを作成してloofahを2.20になるようにするのがよい。
gem 'loofah', '~> 2.20.0'
こうすれば、2.20系の最新版が選択され、Nokogiriとのバージョン不整合も発生しなくなる。
前の記事では、案2としてRedmineのGemfileを修正する、ということも書いていたが、後述するとおり、新しいRedmineではNokogiriのバージョンの指定も上がっているため、この問題は発生しない。逆にあえてその時にNokogiriのバージョン指定が1.11になっているということは、それ以上のバージョンに上げた場合のテストがされていないことを意味しているため、勝手にRedmineのGemfileのバージョン指定を書き換えることはオススメできない。
loofah 2.21.0がリリースされた後にのみおこる問題であるため、それを抑止するのが適切な対処である。
この問題は(loofah 2.21がリリースされた後)Ruby、Redmineのバージョンが古い場合にのみ発生する。
事象が発生する環境まとめ
Redmineの各バージョンのGemfileの書き方を調査した結果、RubyのバージョンとRedmineのバージョンで読み込まれるNokogiriのバージョンは以下の通りである。
Nokogiri 1.11以前が読み込まれる環境では問題が発生し、Nokogiri 1.12以上が読み込まれる環境では問題は発生しない。