ActionControllerのメソッドに明示的な&blockパラメータを追加
Rails 8.1では、ActionController内でyieldやblock_given?を使用しているメソッドに、明示的な&blockパラメータが追加されました。この変更は実行時の動作には影響しませんが、静的解析ツールとの互換性と可読性を向上させます。
背景
Railsのコードベースには、ブロックを受け取るメソッドであっても、メソッドシグネチャに&blockパラメータを明示していないものが存在していました。これらのメソッドは内部でblock_given?やyieldを使用してブロックを処理していましたが、Sorbetなどの静的型チェックツールでは「ブロックパラメータを宣言していないメソッドにブロックが渡されている」という警告が発生していました(sorbet/sorbet#9791)。
また、同じファイル内の類似メソッド(each_pair(&block)、each_value(&block)など)では既に&blockが明示されており、一貫性の観点からも改善の余地がありました。
技術的な変更
#56665では、以下のメソッドシグネチャが変更されています。
strong_parameters.rb
変更前:
def fetch(key, *args)
convert_value_to_parameters(
@parameters.fetch(key) {
if block_given?
yield
elsif args.any?
args.first
else
raise KeyError, "key not found: #{key}"
end
}
)
end
変更後:
def fetch(key, *args, &block)
convert_value_to_parameters(
@parameters.fetch(key) {
if block_given?
yield
elsif args.any?
args.first
else
raise KeyError, "key not found: #{key}"
end
}
)
end
同様に、transform_values、transform_values!、each_nested_attributeにも&blockパラメータが追加されています。
live.rb
ストリーミングレスポンスを扱うsend_streamメソッドも更新されました。
変更前:
def send_stream(filename:, disposition: "attachment", type: nil)
# ...
yield response.stream
end
変更後:
def send_stream(filename:, disposition: "attachment", type: nil, &block)
# ...
yield response.stream
end
その他のファイル
-
instrumentation.rb:
cleanup_view_runtime(&block) -
conditional_get.rb:
http_cache_forever(public:, &block) -
mime_responds.rb:
respond_to(*mimes, &block)
設計判断
この変更は後方互換性を完全に維持しています。Rubyでは、メソッドが&blockパラメータを宣言していなくても、yieldやblock_given?でブロックを扱うことができます。逆に、&blockを明示的に宣言しても実行時の動作は変わりません。
PRのチェックリストでは、テストとCHANGELOGの更新がスキップされています。これは、この変更が「no-op(動作に影響しない変更)」であるためです。新しいテストケースを追加する必要がなく、ユーザーに影響する動作変更もないため、CHANGELOGへの記載も不要と判断されています。
静的解析ツールのサポートを向上させつつ、既存のコードベースには一切影響を与えないという、理想的なリファクタリングの例と言えます。生成されるRDocドキュメントにもブロックパラメータが明示されるため、開発者体験の向上にも寄与します。