新規Railsアプリでfrozen_string_literalをデフォルト有効化

rails/rails

新規生成されるRailsアプリに config/bootsnap.rb が追加され、アプリケーションコードに対して frozen string literal がデフォルトで有効になりました。依存ライブラリには影響せず、既存の互換性を維持しながら不要な文字列アロケーションを削減できます。

背景

frozen_string_literal: true マジックコメントはファイル単位での手動付与が必要であり、プロジェクト全体への適用は煩雑でした。また、依存ライブラリも含めて一括で有効化するとまだ対応していない古いgemとの互換性問題が発生するリスクがあります。

Bootsnap #535Bootsnap::CompileCache::ISeq.compiler_selector によるコンパイラの差し替え機能が追加され、app_only: true オプションにより「アプリケーションコードのみに限定してfrozen string literalを適用する」という粒度の制御が可能になりました。このBootsnap側の対応を受けて、Railsはアプリジェネレータにその設定を組み込む形で本PRが作られています。

技術的な変更

本PRはジェネレータ・Gemfile・RuboCop設定の3箇所に変更を加え、新規Railsアプリのfrozen string literal対応を一貫して行います。

config/bootsnap.rb の追加

新たに railties/lib/rails/generators/rails/app/templates/config/bootsnap.rb.tt が追加されました。内容は1行のみです。

# Enable frozen string literal across the app, but not dependencies.
# This configuration should be kept in sync with
# `AllCops/StringLiteralsFrozenByDefault` in `.rubocop.yml`
Bootsnap.enable_frozen_string_literal(app_only: true)

app_generator.rbconfig メソッド内で depend_on_bootsnap? が真のときにこのテンプレートが生成されます。

# 変更後(抜粋)
template "bootsnap.rb" if depend_on_bootsnap?

Gemfileのバージョン制約追加

Bootsnap.enable_frozen_string_literal は新しいAPIであるため、Gemfile.tt のbootsnap依存に下限バージョン >= 1.24 が追加されました。

-gem "bootsnap", require: false
+gem "bootsnap", ">= 1.24", require: false

RuboCop設定との同期

rubocop.yml.tt にも AllCops/StringLiteralsFrozenByDefault: true が追加されました。これにより、コードがfrozen string literalを前提としていることをRuboCopが認識し、対応するオフェンスを正しく検出できます。コメントで config/bootsnap.rb との同期を保つよう明示されており、どちらか一方を変更する際に他方も合わせる必要があることが伝わるようになっています。

AllCops:
    # This configuration should be kept in sync with `config/bootsnap.rb`
    StringLiteralsFrozenByDefault: true

テストとして test_inclusion_of_bootsnap_filesapp_generator_test.rb に追加され、config/bootsnap.rb が生成されることを保証しています。

設計判断

アプリコードのみに限定する という方針が明示的に選択されています。

PR説明では、依存ライブラリへの適用も技術的には可能だが一部の古いgemが未対応である可能性があるため、app_only: true によりアプリコードのみに絞っています。これにより、互換性リスクを最小化しながらfrozen string literalの恩恵をアプリ開発者に届ける設計です。

設定ファイルを config/initializers/ ではなく config/bootsnap.rb として独立させている点も注目に値します。config/boot.rb から早期にロードされるBootsnap自体の設定は、Railsの初期化サイクルより前に実行する必要があるため、initializersに置くよりも独立ファイルとして管理するのが適切です。また bootsnap.rb.rubocop.yml の両方にコメントで互いを参照させ、設定の一貫性維持を開発者に促している点も実用的な判断です。

bootsnapを使用しない構成(--skip-bootsnap)では depend_on_bootsnap? が偽になり、この設定ファイルやRuboCopの追加設定は生成されません。オプトアウト経路が明確に保たれています。

まとめ

Bootsnapの新しいコンパイラ選択機能を活用し、アプリコードに限定したfrozen string literalの適用を新規Railsアプリのデフォルトとした変更です。Gemfileのバージョン制約・RuboCopとのコメント連携・テストの追加まで一貫して整備されており、設定ファイル間の同期を維持しやすい構成になっています。

記事メタデータ

Generated by:
Claude Sonnet 4.6 for DiffDaily
LLM Trace:
beca7b0a

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
Gemini 2.5 Pro for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文、背景、技術詳細、設計判断、まとめという「総論→各論→結論」の構成が明確で模範的です。

カスタムMarkdown構文 ✓ PASS

シンタックスハイライト・GitHubリンク記法の正確性

ファイル名付きコードブロックやGitHubのPRリンク記法が正しく使用されています。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

Railsの内部構造にある程度詳しいエンジニアを対象としており、冗長な初心者向け解説がなく適切です。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクション・各パラグラフが「総論→各論」の構成で書かれており、トピックセンテンスも明確で非常に読みやすいです。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事内のコード引用は、提供されたDiffの内容を正確に反映しており、省略箇所も適切です。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

`frozen_string_literal`, `Bootsnap`, `ISeq` などの技術用語が文脈に沿って正確に使用されています。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

`Bootsnap.enable_frozen_string_literal` が新しいAPIであることとバージョン制約の因果関係など、技術的な説明は論理的かつ正確です。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

記事内のすべての主張は、PRのタイトル、Description、Diff、参照PRから裏付けられており、ハルシネーションは検出されませんでした。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号(#57252)、参照PR番号(#535)、バージョン制約(>= 1.24)など、数値や固有名詞はすべて正確です。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルはPRの主題「Enable frozen string literal by default」を忠実に反映しています。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

PRに記載のない外部知識の捏造はなく、Bootsnapのロードタイミングに関する補足説明も、技術的に自明な範囲での適切な解説です。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

「既に」「将来」などの時間表現の歪曲はなく、事実を正確に記述しています。