`has_json` アクセサが `NoMethodError` を起こす暗黙依存を修正

rails/rails

ActiveModel::SchematizedJson が内部で使用する String#remove メソッドの依存関係が暗黙的であったため、特定のロード順で has_json アクセサが NoMethodError を発生させていました。本PRはその依存を明示的なrequireとして記述することで修正します。

背景

ActiveModel::SchematizedJson は内部で String#remove を呼び出していますが、このメソッドは active_support/core_ext/string/filters によって定義されます。SchematizedJson 自身がこのファイルをrequireしていなかったため、他のコードが先にそのextensionをロードしている環境では正常に動作する一方、active_model 単体でrequireするような環境ではメソッドが見つからず例外が発生するという問題がありました。

以下のスクリプトで main ブランチ上での再現を確認できます:

bundle exec ruby -Iactivesupport/lib -Iactivemodel/lib -e 'require "active_model"; account = Class.new { include ActiveModel::Attributes; include ActiveModel::SchematizedJson; attribute :settings; has_json :settings, restricts_access: true }.new; p account.settings.restricts_access'

フル構成のRailsアプリケーションでは多くのrequireが連鎖してextensionが読み込まれるため、この問題が表面化しにくかったと考えられます。

技術的な変更

active_model/schematized_json.rb の冒頭に1行のrequireを追加することで、依存関係を明示的にしました。

変更前:

# frozen_string_literal: true

require "active_support/core_ext/hash/reverse_merge"
require "active_support/core_ext/symbol/starts_ends_with"

変更後:

# frozen_string_literal: true

require "active_support/core_ext/hash/reverse_merge"
require "active_support/core_ext/string/filters"
require "active_support/core_ext/symbol/starts_ends_with"

active_support/core_ext/string/filters はすでにロード済みの環境では require が二重実行されても無視されるため、既存の動作への副作用はありません。

設計判断

依存するファイルを自身でrequireする という「依存の局所化」原則を徹底する修正です。

ActiveSupportのコアエクステンションはRailsのフル構成では広範にロードされるため、このような暗黙依存は見過ごされがちです。しかし ActiveModel のようなライブラリが単体で使われるケース(スタンドアロンスクリプトや非Railsフレームワークへの組み込みなど)では、ロード順への依存が直接エラーにつながります。修正は1行のrequire追加という最小限の変更ですが、モジュールが自分の依存を自己完結して宣言するという設計の一貫性を回復させています。

まとめ

active_model/schematized_json.rbactive_support/core_ext/string/filters のrequireを追加する1行の変更により、ロード順に依存した脆弱性が解消されました。暗黙的な依存関係は「動いている」うちは問題にならないため見落とされやすいですが、ActiveModelを単体利用する環境では致命的なエラーになりうる点で、今回の明示化は重要な品質向上といえます。

記事メタデータ

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

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

品質レビュー結果

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

Review Criteria:

記事構成 ✓ PASS

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

リード文(総論)→セクション群(各論)→まとめ(結論)の3部構成が明確に守られています。背景、技術的変更、設計判断の各セクションが適切に配置されており、理想的な構成です。

カスタムMarkdown構文 ✓ PASS

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

ファイル名付きシンタックスハイライト(```ruby:path/to/file.rb)とGitHubのPRリンク記法([#123](URL))が正しく使用されています。

対象読者への適合性 ✓ PASS

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

専門用語が適切に使用されており、過度な説明がなく、対象読者である専門知識を持つエンジニアに適した技術レベルで書かれています。

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

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

各セクションが総論→各論で構成され、各段落はトピックセンテンスで始まり、1段落1トピックの原則が守られています。非常に読みやすい文章構造です。

Diff内容との照合 ✓ PASS

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

記事内で引用されているコード(再現スクリプト、変更前後のコード)は、PR情報およびDiffの内容と完全に一致しています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「ActiveModel::SchematizedJson」「NoMethodError」「暗黙依存」などの技術用語が文脈に沿って正確に使用されています。

説明の技術的正確性 ✓ PASS

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

暗黙的な依存関係が原因で`NoMethodError`が発生するという問題の根本原因と解決策が、技術的に正確かつ論理的に説明されています。

事実の突合 ✓ PASS

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

記事内のすべての主張は、PRのDescriptionやDiffの内容に完全に裏付けられています。ハルシネーションは見られません。

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

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

PR番号(#57310)が正確に記載され、正しくリンクされています。

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

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

記事のタイトルはPRの内容を要約しており、問題(NoMethodError)とその原因(暗黙依存)を明確に示していて、主題と一致しています。

外部知識の正確性 ✓ PASS

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

PR情報に含まれていない、バージョンサポート状況やリリース日程などの外部知識の追加はありません。

時間表現の正確性 ✓ PASS

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

「〜でした」「〜という問題がありました」など、PRの文脈に合った正確な時間表現が使われています。