ActiveStorage::FixtureSetで生成されるキーのテナントプレフィックス欠落に対応
ActiveStorage::FixtureSetが生成するBlobキーには、テナントプレフィックスが付与されないため、Tenanted::DiskService#path_forがパス分割に失敗する問題が修正されました。テナントプレフィックスのないキーに対して、標準のDiskServiceの挙動にフォールバックすることで、Fixtureを用いたテストが正常に動作するようになります。
背景
activerecord-tenanted では、テナント分離を実現するために、ActiveStorageのBlobキーにテナントプレフィックスを付与する仕組みが実装されています。通常、キーは tenant_name/blob_key の形式となり、path_for メソッドはこの形式を前提に / で分割してテナントディレクトリとBlobキーを取得していました。
しかし、ActiveStorage::FixtureSet.blob が生成するBlobキーには、このテナントプレフィックスが含まれません。そのため、path_for メソッド内で / による分割を試みると、folder_for メソッドで NoMethodError が発生していました。この問題により、Fixtureを使用したテストケースが実行できない状況が生じていました。
技術的な変更
lib/active_record/tenanted/storage.rb の path_for メソッドに、キーにテナントプレフィックスが含まれているかを判定する条件分岐が追加されました。
変更前:
def path_for(key)
if ActiveRecord::Tenanted.connection_class
# TODO: this is brittle if the key isn't tenanted ... errors in folder_for:
#
# NoMethodError undefined method '[]' for nil (NoMethodError) [ key[0..1], key[2..3] ].join("/")
#
tenant, key = key.split("/", 2)
File.join(root, tenant, folder_for(key), key)
else
super
end
end
変更後:
def path_for(key)
if ActiveRecord::Tenanted.connection_class && key.include?("/")
tenant, key = key.split("/", 2)
File.join(root, tenant, folder_for(key), key)
else
super
end
end
key.include?("/") による判定が追加され、テナントプレフィックスを含まないキーの場合は super で親クラス(標準の ActiveStorage::Service::DiskService)の実装にフォールバックするようになりました。これにより、Fixtureで生成されたキーでも正しくパスが解決されます。
テストケースでは、以下のようなFixture定義が追加されています:
Blob Fixture:
one_image_blob: <%= ActiveStorage::FixtureSet.blob filename: "goruco.jpg", service_name: "test" %>
Attachment Fixture:
one_image:
name: image
record: one (Note)
blob: one_image_blob
このFixtureを利用した統合テストが test/integration/test/active_storage_test.rb に追加され、Fixtureが正常に読み込まれることが検証されています。
設計判断
キーの形式による条件分岐 という単純な判定手法が採用されました。
コード内のTODOコメントにあるように、テナントプレフィックスのないキーへの対応は既知の課題でしたが、今回は最小限の変更で問題を解決する方針が取られています。key.include?("/") による判定は、テナントプレフィックスの有無を直接的に判断する方法であり、既存のテナント付きキーの処理には影響を与えません。
より厳密な判定方法(正規表現パターンマッチングや、キーの生成元を追跡する仕組みなど)も考えられますが、Fixtureのキーは通常のランタイムで生成されるキーとは異なる経路で作られるため、シンプルな形式判定で十分に機能します。標準のDiskServiceへのフォールバックにより、Fixtureだけでなく、他の理由でテナントプレフィックスを持たないキーが存在した場合にも柔軟に対応できます。
まとめ
本PRは、テナント分離を実現する path_for の実装に、テナントプレフィックスのないキーへの対応を追加した変更です。キーの形式チェックを追加するだけで、Fixtureベースのテストを可能にしつつ、既存のテナント分離機能との互換性を維持しています。この修正により、テスト環境と本番環境の両方で一貫したActiveStorageの動作が保証されます。