ActiveStorageの画像URLをテストする方法
2025年もついに明けてしまいましたね...
なにこれ
Ruby on RailsにはActiveStorageというとても便利なライブラリがあります。
ActiveStorageで保存した画像のURLをテストする際のTipsを記事にしたものです。
問題
ActiveStorageでは public: true
をしない限り、ファイルを表示したりDLする際のURLを一時的なURLにします。
> hoge.image.url
=> "http://example.com/rails/active_storage/disk/eyJfcmFpbHMiOnsiZGF0YSI6eyJrZXkiOiJwdGw3a2FjcmN4MnU0NHJ4b2lnaGw3YTlla3E0IiwiZGlzcG9zaXRpb24iOiJpbmxpbmU7IGZpbGVuYW1lPVwic2NyZWVuc2hvdC5wbmdcIjsgZmlsZW5hbWUqPVVURi04JydzY3JlZW5zaG90LnBuZyIsImNvbnRlbnRfdHlwZSI6ImltYWdlL3BuZyIsInNlcnZpY2VfbmFtZSI6InByaXZhdGUifSwiZXhwIjoiMjAyNS0wMS0wN1QxMDo0MDo0NS4wMzZaIiwicHVyIjoiYmxvYl9rZXkifX0=--bc22b1b05e742b0209cfc68032987d586cd5059d/screenshot.png"
(テスト環境なのでdiskにファイルがあります)
このURLは一時的なURLであるため再度URLを吐き出すとURLが変わります。
> hoge.image.url
=> "http://example.com/rails/active_storage/disk/eyJfcmFpbHMiOnsiZGF0YSI6eyJrZXkiOiJwdGw3a2FjcmN4MnU0NHJ4b2lnaGw3YTlla3E0IiwiZGlzcG9zaXRpb24iOiJpbmxpbmU7IGZpbGVuYW1lPVwic2NyZWVuc2hvdC5wbmdcIjsgZmlsZW5hbWUqPVVURi04JydzY3JlZW5zaG90LnBuZyIsImNvbnRlbnRfdHlwZSI6ImltYWdlL3BuZyIsInNlcnZpY2VfbmFtZSI6InByaXZhdGUifSwiZXhwIjoiMjAyNS0wMS0wN1QxMDo0MTozMC4xNDFaIiwicHVyIjoiYmxvYl9rZXkifX0=--3c8b5e764d1c91b1107d440001ccdded04cdfaa2/screenshot.png"
↑の仕様だと、APIモードなどでRailsを動かしていてレスポンスが正しいかをテストする際に期待値と異なるためテストできねぇとなったのが今回の問題です。
解決方法
解決方法はいとも簡単で、一時的なURLは現在の時刻をベースにURLを生成しているため
before { freeze_time }
をテストの最初に入れれば解決します!!
ActiveStorageのコード
テスト時はAWS等の外部サービスではなくDiskサービスをしている事が多いと思います。
DiskサービスのURLを生成している箇所は以下です。
private_url
が public: true
にしていない場合は呼ばれ、 generate_url
で実際にURLを生成しています。
rails_disk_service_url
は以下で宣言されています
↑はURLヘルパーのコードだったので generate_url
に戻ります。
ActiveStorage.verifier.generate
は以下です。
serialize_with_metadata
の返り値をencodeしているっぽいですね...
serialize_with_metadata
は以下です。
generate_url
ではhashのあとに expires_in
を blob_key
を渡しているので wrap_in_metadata_legacy_envelope
が呼ばれそうです。
その後に serialize_to_json
を呼んでいますね。
という感じで expires_in
を使ってencodeしたURLを生成しているっぽいですね... (分かった顔
public: true
の場合は expires_in
がnilなので生成したタイミングでURLの変更はなさそうです。
よいテストライフを!!
Discussion