カレーの恩返し

おいしいのでオススメ。

marginalia(ActiveRecord::QueryLogs) を使うと ActiveRecord::Relation#explain が空文字を返す問題

困っている人向けまとめ


marginalia を使おうとしたときにちょっと困ったことがあったのでメモ書き。

marginalia とは

marginalia gem とは、rails/rails を作った basecamp が作った gem で SQL のクエリの先頭か末尾にどの controller / action で発行されたかをクエリのコメントとして追記してくれる機能を持っている。

また、この機能は Rails 7 では ActiveRecord::QueryLogs という名前で標準の機能に取り込まれている。便利で使ってたけどメンテされてる気配がなかったので標準に取り込まれるのは嬉しい。

api.rubyonrails.org

どんな問題が起きたのか

marginalia のデフォルトの挙動では、クエリ発行位置をクエリの末尾にコメントするようになっているが下記のように prepend_comment option を true にするとクエリの先頭にコメントを追記してくれるようになる。

Marginalia::Comment.prepend_comment = true

これを設定した上で ActiveRecord::Relation#explain(e.g. User.all.explain) を実行すると、explain 結果が空文字になってしまう問題が起きていた。

この問題は既知で、ActiveRecord::Relation#explain は with, select, update, delete, insert のいずれかから始まるクエリでないと EXPLAIN が動作しないような実装になっているのが原因とのこと。

github.com

どう対応すればいいのか

既に rails/rails に修正は取り込まれているものの、2022/12/27 時点の Rails 最新版である 7.0.4 ではまだ反映されていないので変更に対応する monkey patch をあてる必要がある。具体的には以下。

# config/initializers/marginalia.rb

# `Marginalia::Comment.prepend_comment = true` で marginalia を動かすと `ActiveRecord::Relation#explain` が空文字を返す問題の対応。
# 対応自体は https://github.com/rails/rails/commit/a32c54e49e46f08a910a993718bae78e57f3d85f で rails/rails の main branch に取り込まれている。
# 2022/12/27時点でのRails 最新バージョン(7.0.4)には取り込まれていないので、取り込まれたバージョンまで Rails が上げることができればこの monkey patch を消すことができる。
if defined?(ActiveRecord::ExplainSubscriber) && ActiveRecord::ExplainSubscriber.const_defined?(:EXPLAINED_SQLS)
  ActiveRecord::ExplainSubscriber::EXPLAINED_SQLS = /\A\s*(\/\*.*\*\/)?\s*(with|select|update|delete|insert)\b/i
end