`ReflectionProxy#all_includes` が `strict_unused_block` 警告に対応
Ruby 3.4の strict_unused_block 警告カテゴリへの対応として、ReflectionProxy#all_includes に匿名ブロック転送を追加しました。動作変更はなく、警告の抑制のみが目的です。
背景
Ruby 3.4の strict_unused_block 警告カテゴリを有効化したところ、ReflectionProxy を含む関連がロードされるたびにActive Record自身が警告を発することが判明しました。ReflectionProxy#all_includes は呼び出し元の add_constraints からブロックを受け取りますが、意図的にそのブロックを破棄するno-opメソッドです。しかし、ブロックパラメータを宣言していなかったため、strict_unused_block がこれをフラグとして検出していました。
RailsチームはBuildkiteのCI環境でこの警告カテゴリを有効にしており、実運用に近い環境での検出が今回の修正につながっています。
技術的な変更
変更は activerecord/lib/active_record/associations/association_scope.rb 内の ReflectionProxy クラスの1行のみです。
変更前:
def all_includes; nil; end
変更後:
def all_includes(&); nil; end
Rubyの 匿名ブロック転送(anonymous block forwarding) 構文 & を使用しています。& をパラメータとして宣言することでブロックを受け取ることを明示しつつ、メソッド本体では参照しないことで意図的な破棄を表現しています。nil を返す動作自体は変わらず、既存の振る舞いに影響はありません。
設計判断
匿名ブロック転送 & を用いることで、「ブロックを受け取るが転送も保存もしない」という意図をコードレベルで簡潔に示せます。名前付きのブロックパラメータ &block を使うと、未使用の変数 block を定義したように見え、コードの意図が曖昧になるリスクがあります。
この変更は、警告を黙って抑制するのではなく、コードの意図をより正確に表現することで警告の原因を取り除くアプローチをとっています。no-opとして設計されたメソッドであることをコードレベルで明示する形になったといえます。
まとめ
1文字の追加で strict_unused_block 警告を解消したこの変更は、Ruby 3.4の厳格な警告カテゴリとの互換性確保に向けた地道な対応の一例です。匿名ブロック転送という慣用的な構文を選ぶことで、動作の保守性と意図の明瞭さを同時に達成しています。