Active Storage で XML の Content-Type が application/octet-stream になるのを防ぐ #rails

問題

Rails から Active Storage で S3 に XML をアップロードし、CloudFront でホスティングしようとしていた(XMLRSS フィードのようなもの)。

ファイルはアップロードされ、CloudFront 経由でアクセスもできたのだが、ブラウザだとダウンロードされてしまい表示ができなかった。

原因

S3 で当該 XML のプロパティを確認したところ、メタデータがおかしくなっていた。

Content-Dispositionattachment が設定されてしまっており、そのためブラウザでダウンロードになってしまっている。

また Content-Typeapplication/xml を指定しているにも関わらず、application/octet-stream になっていた。

データ( active_storage_blobs )の content_type や S3 でのオブジェクトタイプは問題なかった。

my_model.attach(  
  io: f,  
  filename: 'feed.xml',  
  content_type: 'application/xml',  
  key: 'feed.xml'  
)

対応

Rails の設定を変更することで解決した。

config.active_storage.content_types_to_serve_as_binary

content_types_to_serve_as_binary に設定されている Content-Type は、常に attachement として扱われてしまう。

デフォルトで text/xmlapplication/xml が含まれているので、外してやる必要がある。

config.active_storage.content_types_allowed_inline

content_types_allowed_inline は Active Storageでインライン配信を許可する Content-Type を設定するものだが、application/xml を含めておくようにしないと S3 上でのメタデータも意図したようにならない。

デフォルト値に追加しておくとよい。

# application/xml を削除
config.active_storage.content_types_to_serve_as_binary = %w(text/html image/svg+xml application/postscript application/x-shockwave-flash text/xml application/xhtml+xml application/mathml+xml text/cache-manifest)
# application/xml を追加
config.active_storage.content_types_allowed_inline = %w(image/webp image/avif image/png image/gif image/jpeg image/tiff image/vnd.adobe.photoshop image/vnd.microsoft.icon application/pdf application/xml)

まとめ

設定を変更することで、問題なく表示されるようになった。

一律でなくファイルによって個別に対応する必要があるような場合は、都度設定を切り替えるようにすればできそう(調べていない)。

参考