← Back to list

Do you care about ContentDisposition header in ActiveStorage?

Recently, I ran into an interesting problem: Some of the PDF files on my work project’s opened directly in the browser but some downloaded.

Eugene Melnic · 2025-09-25 19:29 · 0 claps · 1.4 min read
#active-storage #ruby-on-rails #aws-s3 #download #inline
Open on Medium ↗
Wiki topics: RAG · RAG & Retrieval 🌐 · Web Development ☁️ · DevOps & Cloud

Do you care about Content Disposition header in Active Storage?

Recently, I ran into an interesting problem: Some of the PDF files on my work project’s website opened directly in the browser (inline), while others were downloaded.

The project itself is pretty old, it had started with Rails 5 and was upgraded to 6 and then 7 version over last 8 years. Somewhere along the way, some configuration got out of sync.

Check Rails configuration

Rails has a setting for which file types can be shown inline:

config.active_storage.content_types_allowed_inline = [
 “image/png”,
 “image/jpeg”,
 “image/gif”,
 “image/webp”,
 “application/pdf”
]

After upgrading to Rails 7, I made sure application/pdf was added to this list.

What about S3?

In our case, files are stored in public AWS S3 bucket. We don’t proxy files through Rails with rails_blob_path or redirects. Instead, customers get a direct link to the file on S3 or Cloudfront CDN depending on our needs.

At first, my idea was simple - use Rails helper like this:

rails_blob_path(attachment, disposition: “inline”)

But this only works if the file doesn’t already have a Content-Disposition: attachment header set in S3 metadata (Interesting fact that this header is set as System). And of course, a lot of old files had it.

So even with the Rails config fixed, the browser was still forcing downloads.

Debug

Before changing anything, it’s useful to check what headers a file has:

s3 = Aws::S3::Client.new(
 region: “your-region”
 access_key_id: ENV[“AWS_ACCESS_KEY_ID”],
 secret_access_key: ENV[“AWS_SECRET_ACCESS_KEY”]
)

bucket = "your_bucket_name"
key = "your_file_key"

response = s3.head_object(bucket: bucket, key: key)
response.content_disposition

If you see attachment, that’s the reason your PDF is being downloaded.

Fixing old files

Unfortunately, you can’t just update metadata in place on S3. The trick is to copy the file onto itself with updated metadata:

resp = s3.head_object(bucket: bucket, key: key)

s3.copy_object(
 bucket: bucket,
 key: key,
 copy_source: "#{bucket}/#{key}",
 metadata_directive: 'REPLACE',
 content_type: resp.content_type,
 content_disposition: nil, # remove "attachment"
 metadata: resp.metadata # keep custom metadata
)

response = s3.head_object(bucket: bucket, key: key)
response.content_disposition

Now the file doesn’t force download anymore. Browsers will open it inline.

Once content_types_allowed_inline is configured correctly, and old files are fixed, all new uploads will work fine too.

That’s it. Now, your users will see PDFs open directly in their browser instead of automatically downloading.


메타데이터
post_id
031f89d75cd2
slug
do-you-care-about-contentdisposition-header-in-activestorage-031f89d75cd2
url
https://medium.com/@melnic404/do-you-care-about-contentdisposition-header-in-activestorage-031f89d75cd2
canonical_url
https://medium.com/@melnic404/do-you-care-about-contentdisposition-header-in-activestorage-031f89d75cd2
author_url
https://medium.com/@melnic404
status
ok
fetched_at
2026-07-17 07:03:26