祝RC1!! Rails7.0 でRedmine を動かしてみた
この記事は Redmine Advent Calendar 2021 の9日目の記事になります。前日の記事は、tohosakuの「プラグイン を Redmine 4.* でも 5.0 でも動かすためには」でした。二日連続でおつきあい下さい。
Rails 7.0 RC1 がやってきた
2日前の早朝[1]、Ruby on Rails の公式ブログにRails 7.0 RC1: New JavaScript Answers, At-Work Encryption, Query Origin Logging, Zeitwerk Exclusivelyという記事が投稿されました。"Rails 7.0 RC1" 、確かにそう書かれています。
Rails7.0 は、およそ三ヶ月前、9/16に異例のalpha版が発表された状態でした。つまりこちらとしては、次は betaだと思ってました。beta2回、RC2回、最後のRC2が修正されずにリリースとかそんな感じだと。それが突然 "Release Candidate"!!
しかも昨日も書きましたが記事は以下のように結ばれています。
We hope to get this work in the hands of everyone before Christmas this year 🎄🎁❤️.
つまり、この Advent Calendar が終了するころには出ているかもしれません。Rails7。
実は先月半ばにとある理由から、Rails7.0-alpha2上で Redmine を動かすため試行錯誤していました。その時点では「どうせ、またガラッと変わるだろうから」と動いた branch を放置していたわけですが、事態の急転に驚き、branchをRedmineの最新のmasterにrebaseして rails test
してみました。
結果、以前は見なかった新たな DEPRECATION WARNING が表示されるようになったものの、rails s
で Redmine が起動するところまでは確認しました。先月の対応の記録と Redmine 修正中に便利だと思ったツールの使い方などを紹介していきたいと思います。
過程はともかく現在の対応状況を見たい、という奇特な方は、github の fork をごらんください。
alpha2 の時点で対応した WARNINGや変更
機械的な置き換えで対応できたもの
ActiveRecord::Base.default_timezone= is deprecated and will be removed in
Rails 7.1.
Use ActiveRecord.default_timezone= instead.
Rails 7.1 will return Content-Type header without modification. If you want just
the MIME type, please use #media_type instead.
Implicit conversion of User into String by
ActiveSupport::SafeBuffer is deprecated and will be removed in Rails 7.1. You must
explicitly cast it to a String.
このあたり、警告は出ますが対処法も親切に明示されているので機械的に置きかえました。
Rails公式でも「謎」とされていた仕様の修正
本家のプルリク "Deprecate ActiveSupport::TimeWithZone.name #41835" で
The reasoning for this is unclear and it can cause confusion for developers
とか
we don't know why this was added
とか言われている機能を Redmine も使っていました。上記のリンクの中では、XML出力に対応するための機能では?と言われています。Redmine ではチケットの様々な属性を数値、文字列、時間など型に応じて指定フォーマットで変換する部分に使われていました。
エラーを元に検索する中で日本語の記事にもなっているのを発見しました。
Rails公式が使わなくなった gem を Redmine が使っている
Redmine が使用している actionpack-xml_parser
と roadie-rails
という2つの gem は bundle update
の時点で依存関係のエラーを起こしました。github 上の最新の master や fork に修正したものがあったので、Gemfile で github を参照するように修正しました。
手元で動かす分にはこれで良いでしょうが、Redmine公式では対応方法の検討が必要でしょう。
難物だったもの
今年8月にマージされたパフォーマンス向上のための修正で、通常のRailsアプリには影響なさそうですが、Redmineの API には影響甚大な変更でした。
Redmine では、xml または json 形式の API のリクエストを受け付けると、app/views/
以下で .api.rsb
という拡張子のテンプレートを検索して独自の処理をほどこし、json や xml を返します。issues.json
が欲しい、とリクエストすると app/views/issues/index.api.rsb
が呼びだされます。html で issues/
をリクエストすると、app/views/issues/index.html.erb
が使われるのと同じような感じです。
ここで、「json、xml 共通で .api という拡張子へのリクエストとみなす」という部分も「そのときのテンプレートとして .rsb というものを使用する」というのも Redmine独自の仕様で、Rails本体にモンキーパッチを当てることで実現しています。[2]
ところが、Rails公式では応答を返すときのテンプレート探索で、あらかじめ登録された mimetype を使ってより厳密にテンプレートを絞りこむようになってしまいました。この余計な候補を探さない、というのがパフォーマンス向上の手段だったようです。
「.api という拡張子を仮に mimetype に仕込む」とか色々考えたんですが、結局、モンキーパッチを当てる部分を増やすことで対応しました。
このプルリクがマージされる過程では、特に「困る人が出るかもしれない」とかいう議論もなく、Rails7.0の Changelog でも全く触れられていません。この部分では、Redmine というのはよほど独特なことをしているんだな、と思いました。
対応の中で得たコードリーディングの小技
上記のテンプレート探索関連の修正対応では、Redmine というよりも Rails本体がどう動くのか、というのを追いかけるのに時間がかかりました。
ここで役に立ったのが、rubyのデバッガでした。[3]
デバッガは、通常は自分の書いたコードにdebugger
とか書きこむ形でブレークポイントを設定するものとして紹介されています。今回は、Railsの動きがあまりにも分からず、トレースに表示された Rails のコードのパス名をコピーし、デバッガのcli画面でb
コマンドでブレイクポイントを設定して、処理の流れやその時点での変数を調査する、ということを繰り返しました。
しかし、これも Rails 起動のたびに毎回ブレークポイントを設定するのが非常に面倒で、何か良い方法がないか、と ruby/debug
のドキュメント を読み直してみました。すると
You can specify the initial script with rdbg -x initial_script (like gdb's -x option).
という記述がありました。つまり
# b /usr/local/bundle/gems/actionpack-7.0.0.alpha2/lib/action_controller/metal/mime_responds.rb:276
b /usr/local/bundle/gems/actionview-7.0.0.alpha2/lib/action_view/rendering.rb:129
と ./rdbrc.txt
の中にブレークポイントのファイル名、行数を書いておいて、
rdbg -x ./rdbgrc.txt -c -- rails server
とすると、rails 起動時点ですでにブレークポイントが設定されている!!しかも、ファイルの中ではコメントアウトもできる。これは公式に何の記述もありませんが[4]、できたら良いなと思いつつやってみて上手く行ったときは感動しました。
これで、ブレークポイントの条件を細かく変えるときも前の条件をコメントの形で残して後から比較できるし、コマンドファイルにコメントで「調べたいこと」や「調査の結果」「日時」とかをどんどん追加していけば、それが一種の航海日誌(ログ)になるわけです。
入門記事などで、コードに挿入する感じのデバッガの使い方ばかりを読んでいた身としては、「こういう使い方誰かに教えてほしかった」という気分です。
おまけ
最初の方で、「とある理由で rails7 alpha2 を……」と書きましたが、なぜこんなことをしようとしたか、について一言。
Rails7 と並んで、おそらく今後の Rails開発に大きな影響を与えるであろう Hotwire。そのプルリクの中で、気になる機能がありました[5]。
Hotwire の一部である Turbo Frames の機能なんですが、簡単に言うと、ページの間の移動のような url の変更をともなうブラウザのナビゲーションであっても、ページ全体をリライトすることなく、一部のみを再描画することが可能ということ。
つまり、javascriptをいろいろ書いたりすることなしにRedmine のチケット一覧で検索したり、ページを移動したりする場合でもチケット一覧だけが書き換えられてリロードを発生させずに済む。というわけです。RedmineはどうもUIが、とか言われずにすむかもしれない!! これを試してみたかった。ただ、その後、色々忙しくなってこっちは全く手を付けていないのでした。
Discussion