Rails.app.dotenvs が明示的なパスを正しく尊重するよう修正

rails/rails

Rails.application の dotenvs アクセサは、デフォルト以外の .env ファイルを指定できるように path 引数を受け取りますが、従来はインスタンスが一度だけ @dotenvs ||= で生成されていたため、最初の呼び出しで渡したパスしか保持されませんでした。結果として、開発環境で Rails.app.creds が先に参照された後に別のパスを指定すると、期待した設定が取得できずにデフォルトの内容が返ってきました。

背景

Rails.application#dotenvspath 引数で任意の .env ファイルを読み取れる設計でしたが、実装は @dotenvs ||= ActiveSupport::DotEnvConfiguration.new(path) という形でインスタンスを単一化していました。この単一化により、最初に呼び出されたパスがメモ化キーとなり、以降の呼び出しで異なるパスが渡されても無視される挙動が発生しました。

開発モードでは Rails.app.creds が内部で dotenvs(デフォルトパス)を呼び出すため、最初に creds が評価されるとデフォルトの .env が固定化されます。その後、Rails.app.dotenvs("/path/to/custom.env") を実行しても、デフォルトの .env 設定が返される というサイレントなバグが起きました。テストケースでも同様に、デフォルト取得後にカスタムパスを指定すると期待通りのキーが取得できないことが確認されています。

技術的な変更

dotenvs の実装を パス単位でのメモ化 に変更し、@dotenvs をハッシュにして path をキーに保持するようにしました。新しい実装は次の通りです。

def dotenvs(path = Rails.root.join(".env"))
  (@dotenvs ||= {})[path] ||= ActiveSupport::DotEnvConfiguration.new(path)
end

変更前は @dotenvs ||= ActiveSupport::DotEnvConfiguration.new(path) という単一インスタンスの生成でしたが、変更後は @dotenvs ||= {} でハッシュを初期化し、@dotenvs[path] ||= ... でパスごとにインスタンスをキャッシュします。この差分により、同一パスの再呼び出しは同一オブジェクトを再利用しつつ、異なるパスは別個のオブジェクトが生成されます。

@dotenvs はこのメソッド以外で参照されていないため、ハッシュへ置き換えても既存コードへの影響はありません。テスト dotenvs honors an explicit path even after the default has been accessed が追加され、デフォルト取得後でもカスタムパスが正しく反映されることを自動的に検証しています。

設計判断

この修正は 「パスを受け取りつつメモ化する」 というアクセサの一貫性を保つ選択です。encrypted(path, …) は毎回新規インスタンスを返す一方、credentials はメモ化のみでパス概念がなく、dotenvs は両方の要素を持つハイブリッドでした。テーブルで示されたように、dotenvsmemoization key を path にする ことは、既存パターンと整合しつつ期待動作を実現する最小変更です。

このアプローチは後方互換性を保持します。Rails.app.dotenvs を引数なしで呼び出す既存コードはハッシュのデフォルトキー Rails.root.join('.env') を利用し、従来通りのインスタンスが取得されます。新たにパスを指定するケースだけがハッシュに別エントリを作成するため、パフォーマンスへの影響は限定的です。

まとめ

Rails.application#dotenvs のメモ化ロジックをパスキー付きハッシュへ変更したことで、明示的な .env パスが正しく尊重されるようになりました。これにより開発環境での Rails.app.creds との相互作用も安全になり、アクセサの設計意図に沿った一貫した動作が保証されます。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
ba29351c

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

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

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

リード文・背景・技術的変更・設計判断・まとめの5セクションで構成され、総論→各論→結論の流れが明瞭です。

カスタムMarkdown構文 ⚠ WARNING

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

コードブロックはファイル名付きハイライトが正しく使用されていますが、PRリンクが "[PR #57787]" となっており、フォーマットは "[#57787]" が推奨です。コミットIDのリンクが無い点も軽微な欠落とします。

対象読者への適合性 ✓ PASS

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

Rails エンジニア向けの専門的な記述で、初心者向けの過度な説明はありません。

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

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

各セクションの冒頭がトピックセンテンスとなっており、1段落1トピック・6文以内に収まっています。段落間も空行で区切られています。

Diff内容との照合 ✓ PASS

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

記事内コードは Diff の変更内容を正確に反映しており、ハッシュ初期化とパス別キャッシュのロジックが示されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

memoization、ハッシュ、パスキー などの用語が PR と一致し、誤用はありません。

説明の技術的正確性 ✓ PASS

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

技術的な説明は PR の要点と合致し、因果関係も正しく記述されています。

事実の突合 ✓ PASS

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

追加されたテスト名や動作確認の記述は PR の Diff に含まれており、根拠のない主張はありません。

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

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

PR 番号 #57787 が正しく記載されており、他の数値や固有名詞の誤りはありません。

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

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

記事タイトルは PR の要旨「explicit path argument を尊重する修正」を正確に日本語化しています。

外部知識の正確性 ✓ PASS

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

バージョンサポートやリリース予定等、PR に記載されていない外部情報は含まれていません。

時間表現の正確性 ✓ PASS

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

時間表現のずれはなく、PR の記述と一致しています。