https://github.com/rails/rails
Active Recordのマルチパラメータ属性代入(`Date` 型などに使われる `"last_read(1i)"` 形式)で `nil` を渡すと `NoMethodError` が発生していた問題を修正。`value.empty?` を `value.blank?` に変えるだけの1行修正で、`nil` と `""` が意味的に等価として扱われるようになりました。
Active Support のテストケースに `around` コールバックが追加され、`setup` と `teardown` の間を跨いだコンテキスト管理を1つのブロックで記述できるようになりました。`ActiveSupport::Callbacks` の仕組みを活用した実装であり、外部 gem 不要で Minitest ベースの Rails テストで `around` フックが利用できます。遅延インクルードにより、`around` を使わないクラスへの副作用も局所化されています。
RailsのTag Builderで、`data`や`aria`以外の任意のキーに対してもHashをネストするとダッシュ区切りのHTML属性に展開されるようになりました。`hx:`や`x:`といったキーを使えるようになり、htmxやAlpine.jsとの連携が宣言的に書けます。変更の核心は属性展開の判定ロジックをホワイトリスト(`data`のみ)からブラックリスト(`aria`と`class`以外はすべて)に反転させたことです。
`rails new` が生成する Gemfile で、デプロイツールの Kamal gem がトップレベルから `group :development` に移動されました。これによりプロダクションバンドルへの不要な Kamal の混入が防がれ、`--skip-dev-gems` オプションとの動作一貫性も確保されています。
`Hash#keys.each` が生成する中間配列を排除するため、Railsコードベース内の複数箇所で `Hash#each_key` に置き換えました。PRのDescriptionでは2箇所(`schematized_json.rb` と `dirty.rb`)とされていましたが、最終的なDiffはテストファイル2つを含む計3ファイルの変更となっています。なお、ループ内でハッシュを変更している残り3箇所は安全性の観点から意図的に対象外とされています。
`validates_uniqueness_of` でバリデーション失敗時に `errors.details` へ `:existing_id` キーが追加され、競合を引き起こしているレコードのプライマリキーを取得できるようになりました。内部実装では `.exists?` から `.pick(primary_key)` への置き換えで実現しており、パフォーマンスへの影響もほぼありません。JSON APIでの競合リソース参照など、より具体的なエラーレスポンスの構築が可能になります。
Active Jobに`ActiveJob::Attributes`モジュールが追加され、Active Model Attributesを使って型付きの属性値をジョブのシリアライズ・デシリアライズをまたいで保持できるようになりました。`ActiveJob::Continuable`にデフォルトでincludeされ、`attribute`マクロでステップ間・リトライ間をまたいで引き継ぐデータを宣言的に定義できます。
Rails 8.1で`ActionMailer::Base.mail`をクラスレベルで直接呼び出すと`AbstractController::ActionNotFound`が発生するリグレッションが修正されました。`action_methods`を条件付きでオーバーライドして`"mail"`をアクションとして認識させることで、Rails 8.0の動作が復元されます。
`Attached::One` と `Attached::Many` に `as_json` を明示定義し、`has_one_attached` / `has_many_attached` の名前がモデル属性と衝突する際に `record.to_json` が `SystemStackError` を引き起こす問題を修正しました。プロキシが `@record` への後方参照を持つため `Object#as_json` にフォールスルーすると無限再帰が発生していましたが、添付レコードのスカラーカラムを直接返すことでサイクルを断ち切っています。
既存のUserモデルがある状態で認証ジェネレーターを実行すると `db:migrate` が「table already exists」エラーで失敗する問題が修正されました。`create_authentication_files` の冒頭でUserモデルファイルの有無を確認し、既に存在する場合は `CreateUsers` マイグレーションの生成をスキップするよう `AuthenticationGenerator` が改修されています。
Composite Primary Key(CPK)を持つモデルで `eager_load` と `select` を同時に使用すると、SQLのSELECT句に配列を文字列化した不正なカラム名が混入するバグを修正しました。`JoinDependency#aliases` 内の主キー取得処理を `Array()` に統一することで、単一主キー・複合主キー・主キーなしの全パターンを1行で正しく扱えるようになっています。
Railsアプリ生成時の`.dockerignore`テンプレートで、単一階層のglobパターン(`*`)を再帰的パターン(`**`)に統一しました。これにより、Sprocketsキャッシュ、PIDファイル、Active Storageのアップロードファイルなど深くネストされたファイルがDockerビルドコンテキストに混入する問題を修正。冗長な`/tmp/pids/*`と`/tmp/storage/*`パターンも`/tmp/**`に集約されました。
`ActiveSupport::Configurable` の廃止警告メッセージを改善し、画一的な `class_attribute` への誘導から、`attr_accessor`・`class_attribute`・`InheritableOptions` の組み合わせといった複数の代替手段を示す内容に更新しました。要件によって適切な移行先が異なるという実態を反映した変更です。
`ViewReloader#deactivate` と新設の `ReloadersCollection` を導入し、Spring などのフォークプロセスが `app.reloaders.clear` を呼んだ際に `file_system_resolver_hooks` のフックも確実に除去されるようになりました。これにより、フォーク後のワーカーで `prepend_view_path` のたびに発生していた不要なファイルスキャンが解消されます。
`MemCacheStore` の初期化時に `Dalli::Client` を渡した場合、これまで引数バリデーションをパスしてしまっていましたが、明示的な `ArgumentError` を発生させるよう修正されました。`Dalli::Client` のサポートは以前のコミットで既に削除されており、バリデーションロジックとエラーメッセージの整合性を回復する変更です。
`ActionView::CacheExpiry::ViewReloader` において、ビューパスが未登録の状態でウォッチャーが早期構築されてしまう問題を修正しました。フック登録タイミングをコンストラクタからRailtieの初期化処理へ移動し、空パスでのウォッチャー構築をスキップするガード節を追加することで、Spring のようなプリローダー環境での不要なファイルシステムスキャンを排除します。Shopifyの計測では wall-time が 29% 削減されています。
minitest の `assert_nil` が `nil == obj` による同値比較に変更されたことで、`nil?` が `true` を返す null オブジェクト(`Mime::NullType` など)のテストが失敗するようになりました。本PRは `assert_nil` を `assert_equal true, obj.nil?` に置き換え、null オブジェクトパターンの契約をテストコードに正確に反映させるテスト専用の修正です。
`ActiveRecord::Persistence#becomes` でSTIモデルを型変換した際に `marked_for_destruction` フラグが失われるバグが修正されました。`@new_record` や `@destroyed` と同様に `instance_variable_set` で1行追加するだけの最小限の修正で、ネストされたフォームや一括操作での破棄処理の整合性が確保されます。
新規生成されるRailsアプリに `config/bootsnap.rb` が追加され、アプリケーションコードに対してfrozen string literalがデフォルトで有効になりました。Bootsnapの `app_only: true` オプションを活用することで、依存ライブラリへの影響を避けつつアプリコードのみに適用する設計が採用されています。Gemfileのバージョン制約(>= 1.24)とRuboCop設定の同期も合わせて行われており、一貫した構成が整備されています。
複数の`constraints`ブロックをネストした場合に最内側の制約のみが有効になっていたバグを修正。`mount`メソッド内でスコープ由来の制約と`:constraints`オプションを明示的にマージする処理を追加することで、すべての制約がAND条件として正しく評価されるようになりました。Deviseの`authenticate`ヘルパーなど、制約を内部的に使用するライブラリとの組み合わせで特に影響があります。