スキーマ修飾テーブル名のバリデーションをPostgreSQL向けに修正

rails/rails

PostgreSQLのマルチスキーマ構成で schema.rb のロードが失敗する問題が修正されました。validate_table_length! がスキーマプレフィックスを含む長さを測定していたため、有効なテーブル名が誤って拒否されていたバグです。

背景

schema_search_path で複数のPostgreSQLスキーマを使うアプリケーションでは、スキーマダンパーがテーブル名をスキーマ修飾形式で schema.rb に書き出します。db:schema:loaddb:test:prepare がこのファイルを読み込む際に問題が発生していました。

Rails 7.1 で導入された validate_table_length! は、テーブル名がPostgreSQLの識別子長上限(63文字から _pkey の5文字を引いた58文字)を超えていないかを検証します。しかし、schema.rb から渡されるテーブル名が "public.my_table_name" のようなスキーマ修飾形式である場合、スキーマ部分(public. の8文字)を含んだ文字列全体の長さを測定していました。その結果、52文字の有効なテーブル名に public. を付加した59文字の文字列が上限の58文字を超えるとして ArgumentError を発生させていました。PostgreSQL自体はスキーマ修飾のDDLを問題なく受け入れるため、この拒否はRails側のバリデーションのみに起因するものでした(#57093)。

この問題により、マルチスキーマ構成でテーブル名が上限付近にあるアプリケーションでは db:test:prepare が恒久的に失敗する状態になっていました。

技術的な変更

postgresql/schema_statements.rbvalidate_table_length! をオーバーライドするメソッドが追加され、バリデーション前にスキーマプレフィックスを取り除くようになりました。

追加されたコード:

def validate_table_length!(table_name)
  _schema, table_name = extract_schema_qualified_name(table_name)
  super
end

既存の extract_schema_qualified_name メソッドを利用して "public.my_table_name"["public", "my_table_name"] に分解し、スキーマ部分を捨ててテーブル名のみを super に渡します。"my_table_name" だけのスキーマ修飾なしの名前の場合、_schemanil になり、テーブル名そのものが検証されます。

テストコードも同様に更新されています。test_create_table_raises_for_long_table_names において、PostgreSQLアダプター使用時の short_name(上限ちょうどの長さで ArgumentError が発生しない名前)が "public." + "a" * name_limit に変更され、スキーマプレフィックス付きの有効な名前が誤って拒否されないことを検証するようになりました。

-    short_name = "a" * name_limit
+    short_name =
+      if current_adapter?(:PostgreSQLAdapter)
+        "public." + "a" * name_limit
+      else
+        "a" * name_limit
+      end

設計判断

PostgreSQL固有の schema_statements.rb 内でスーパークラスのメソッドをオーバーライドする方式が採用されています。

基底クラスの validate_table_length! 自体は変更されていません。スキーマ修飾という概念はPostgreSQL固有の機能であり、他のアダプターには影響しないため、修正をPostgreSQLアダプター層に閉じ込める設計が妥当です。また、extract_schema_qualified_name は既存の実装であり、新たなパース処理を追加せずに再利用することで変更範囲を最小限に抑えています。

override後の super 呼び出しにより、基底クラスのバリデーションロジック自体はそのまま維持されます。スキーマ修飾なしのテーブル名に対するバリデーション動作は従来と完全に同一であり、後方互換性を損なう変更はありません。

まとめ

本修正は、PostgreSQLのスキーマ修飾テーブル名という実用的なユースケースに対して、バリデーションレイヤーが正しくスコープを認識できていなかったバグを解消します。アダプター固有のオーバーライドと既存ユーティリティの再利用という最小限の変更で、マルチスキーマ構成アプリケーションの db:test:prepare を正常に機能させます。

記事メタデータ

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

この記事は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のIssue/PRリンク記法が正しく使用されています。

対象読者への適合性 ✓ PASS

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

Railsの内部実装やPostgreSQLに関する専門用語が適切に使用されており、対象読者であるエンジニアに適した技術レベルです。

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

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

各セクションが総論→各論で構成され、各段落はトピックセンテンスで始まり、1段落1トピックの原則が守られています。段落の長さも適切です。

Diff内容との照合 ✓ PASS

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

記事内のコードブロックは、提供されたDiffの内容を正確に反映しており、ファイル名も一致しています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

「スキーマ修飾」「validate_table_length!」などの技術用語が正確かつ文脈に即して使用されています。

説明の技術的正確性 ✓ PASS

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

バリデーションがスキーマ名を含んで長さを計算していたという問題の根本原因と、その解決策(スキーマ名の除去)に関する説明が技術的に正確です。

事実の突合 ✓ PASS

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

記事内の主張はすべてPR情報および関連するIssue(#57093)の内容に基づいており、ハルシネーションは見られません。

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

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

PR番号(#57096)、Issue番号(#57093)、テーブル長の制限文字数などの数値・固有名詞はすべて正確です。

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

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

記事のタイトルは、PRの主題「PostgreSQLのテーブル名長バリデーションでスキーマを無視する」を的確に要約しています。

外部知識の正確性 ✓ PASS

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

「Rails 7.1で導入」といったPR外の情報は、関連Issueに記載されている事実に基づいており、文脈を補うための正確な情報です。

時間表現の正確性 ✓ PASS

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

「修正されました」といった過去形の表現が使われており、PRがマージ済みであるという事実と時間表現が一致しています。