[rails/rails] PostgreSQL接続のリセット時にschema_search_pathが再適用されない問題を修正

rails/rails

Context

Rails 8.1において、PostgreSQLアダプタでActiveRecord::Base.connection.reconnect!を呼び出すか、コネクションプールによる接続リセットがトリガーされた際に、database.ymlで設定したschema_search_pathが再適用されない不具合が発見されました。

この問題は、PostgreSQLが新しいセッションを作成する際にsearch_pathを含むすべてのセッションレベルの状態をリセットするにもかかわらず、PostgreSQLAdapterが以前適用した@schema_search_pathをキャッシュしており、schema_search_path=メソッドが不必要に処理をスキップすることで発生していました。結果として、PostgreSQLはデフォルトの"$user", publicにフォールバックし、複数のスキーマに依存するアプリケーションが正常に動作しなくなっていました。

Technical Detail

問題の根本原因

PostgreSQLAdapter@schema_search_pathインスタンス変数でsearch_pathをキャッシュしていますが、接続がリセットまたは再接続される際にこのキャッシュがクリアされていませんでした。これにより、schema_search_path=メソッド内のガード節が誤って早期リターンし、新しいセッションに対してsearch_pathが設定されない状態が発生していました。

実装された修正

今回の修正では、PostgreSQLのセッション状態が無効化されるタイミングで@schema_search_pathキャッシュをクリアする処理を追加しています。

キャッシュクリア処理の追加:

def clear_cache!(new_connection: false)
  super
  @schema_search_path = nil if new_connection
end

clear_cache!メソッドにnew_connectionパラメータが追加され、新しい接続が確立される場合(PG::Connection#resetによる再接続やDISCARD ALLによるセッションリセット時)に@schema_search_pathをnilにリセットします。

これにより、configure_connectionメソッドが実行される際に、キャッシュされた値が存在しないため、設定されたsearch_pathが正しく再適用されます。

PostgreSQL 18+向けの最適化

def schema_search_path
  @schema_search_path ||=
    with_raw_connection { |conn| conn.parameter_status("search_path") } ||
    query_value("SHOW search_path")
end

PostgreSQL 18以降では、parameter_statusメソッドがsearch_pathをサポートするようになったため、SQLクエリを発行する代わりにこのメソッドを優先的に使用するように変更されました。これにより、不要なネットワークラウンドトリップを削減できます。フォールバックとして従来のSHOW search_pathクエリも保持されています。

テストケースの追加

def test_schema_search_path_is_reapplied_after_reconnect
  db_config = ActiveRecord::Base.configurations.configs_for(env_name: "arunit", name: "primary")

  connection = ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.new(
    db_config.configuration_hash.merge(schema_search_path: "public,foo")
  )

  connection.connect!

  assert_equal "public, foo", connection.select_value("SHOW search_path")

  connection.reconnect!

  assert_equal "public, foo", connection.select_value("SHOW search_path")
ensure
  connection&.disconnect!
end

reconnect!reset!の両方のシナリオに対するテストケースが追加され、接続リセット後もsearch_pathが正しく維持されることを検証しています。

Impact

この修正により、以下の動作が保証されます:

  • reconnect!メソッド呼び出し後もdatabase.ymlで設定したschema_search_pathが維持される
  • コネクションプールによる自動リセット時も設定が保持される
  • 通常動作時の不要なSET search_path呼び出しは回避される(既存のガードロジックが保持されている)
  • PostgreSQL 18以降ではより効率的なparameter_statusメソッドが使用される

この問題はpostgresqlpostgisの両方のアダプタに影響していましたが、この修正により両方で解決されます。

記事メタデータ

Generated by:
Claude Sonnet 4.5 for DiffDaily

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

品質レビュー結果

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

Review Criteria:

ガイドライン準拠 ✓ PASS

記事構成とDiffDaily Styleへの準拠状況

記事構成の3要素(Title, Context, Technical Detail)が明確に記載されています。コードブロック前後の空行やファイル名付きシンタックスハイライトなど、カスタムMarkdown構文も正しく使用されており、可読性が高いです。対象読者であるエンジニアに適した技術レベルで書かれています。

  • 記事構成(Title、Context、Technical Detail)
  • DiffDaily Styleガイド準拠
  • カスタムMarkdown活用
  • 対象読者への適合性
技術的整合性 ✓ PASS

技術的な正確性と表現の適切性

記事で引用されているコードスニペット(clear_cache!, schema_search_path, テストケース)は、PRの変更内容を正確に反映しています。技術用語(schema_search_path, reconnect!, parameter_status)の使用も適切です。問題の原因(キャッシュの未クリア)と解決策(キャッシュのクリア)に関する説明は、技術的に正確かつ論理的です。

  • 技術用語の正確性
  • コード例の正確性
  • 説明の技術的正確性
PR内容との整合性 ✓ PASS

元のPR情報との一致度

記事の内容は、提供されたPR情報(タイトル、番号)と完全に一致しています。PRで解決された課題、実装された修正、さらには関連する最適化(PostgreSQL 18+対応)まで、すべてPRの内容に基づいており、ハルシネーションは見られません。PR番号も正確です。

  • タイトル・説明の一致
  • Diff内容の正確な反映
  • 推測の排除