`app:update` 実行時に `new_framework_defaults` を自動削除する改善
config.load_defaults が現在のRailsバージョンを指している場合、app:update タスクが new_framework_defaults ファイルを不要に再生成しなくなりました。これにより、アップグレード済みアプリケーションでの設定ファイルの散乱が防止されます。
背景
new_framework_defaults ファイルは、Railsバージョンアップ時に新しいデフォルト動作を段階的に有効化するための移行ファイルとして機能しますが、アップグレード完了後は不要になります。従来の app:update は config.load_defaults の値に関わらず常にこのファイルを生成していたため、アップグレード済みアプリケーションで app:update を再実行すると、本来不要なファイルが復元されてしまっていました。
典型的なアップグレードフローでは、開発者は app:update を実行して new_framework_defaults を生成し、その内容を確認・適用した後にファイルを削除して config.load_defaults を新バージョンに更新します。しかしその後、別の設定変更のために app:update を再実行すると、削除したはずの new_framework_defaults が再び生成されるという問題がありました。
PRの説明では、この状況を「使われない new_framework_defaults が大量に存在するのはノイズになる(noisy)」と表現しており、不要ファイルが開発者の混乱を招くことを問題視しています。
技術的な変更
app_generator.rb の config_when_updating メソッドに、new_framework_defaults ファイルを条件付きで削除するロジックが追加されました。
具体的には、現在のRailsバージョンを取得し、remove_new_framework_defaults? ヘルパーメソッドで config.load_defaults のターゲットバージョンと比較します。ターゲットバージョンが現在バージョン以上であれば、ファイルを削除します。
current_version = "#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}"
if remove_new_framework_defaults?(config_target_version, current_version)
remove_file "config/initializers/new_framework_defaults_#{Rails::VERSION::MAJOR}_#{Rails::VERSION::MINOR}.rb"
end
バージョン比較には Gem::Version クラスが使用されており、文字列の単純な比較ではなくセマンティックなバージョン比較が行われます。
def remove_new_framework_defaults?(target_version, current_version)
Gem::Version.new(target_version.to_s) >= Gem::Version.new(current_version.to_s)
end
テストも合わせて更新されており、test_app_update では assert_file が assert_no_file に変更され、load_defaults が現在バージョンを指す場合はファイルが生成されないことを検証するようになりました。また、load_defaults が旧バージョンを指す場合はファイルが生成されることを確認する test_app_update_generates_new_framework_defaults_when_load_defaults_is_previous_version テストが新たに追加されています。
設計判断
削除と生成の両方を app:update が担うという設計が採用されました。app:update はこれまで new_framework_defaults の生成のみを行うタスクでしたが、今回の変更で「アップグレード不要な状態ではファイルを削除する」責務も持つようになりました。
バージョン比較に >= を使用している点は、将来バージョンのデフォルトを先行適用するエッジケースにも対応しています。また、Gem::Version による比較を採用することで、将来的にマイナーバージョンが10以上になった場合でも文字列比較の罠(例: "9" > "10")を避けられます。
削除対象が「現在のRailsバージョンの new_framework_defaults」に限定されている点も注目されます。過去バージョンの new_framework_defaults が残っていても、それは今回の変更の対象外です。これにより変更範囲を最小限に絞り、意図したファイルのみを操作するという保守的な設計になっています。
まとめ
この変更は、app:update の冪等性を高める改善です。config.load_defaults の状態を app:update が考慮するようになったことで、アップグレード完了済みのアプリケーションで繰り返し app:update を実行しても、不要な設定ファイルが生成されない一貫した動作が保証されます。