Generate A Signed Expiring Url For An Active Storage Attachment
Private files — invoices, contracts, medical records — should not be served from a permanent public URL. Active Storage generates signed URLs that expire, so a leaked link stops working.
Description
rails_blob_url produces a URL pointing at your application, which redirects to the storage service. It is signed and expires after ActiveStorage.service_urls_expire_in.
url(expires_in:) on the blob generates a direct service URL — a presigned S3 link that skips your app entirely. Faster for large files, but it cannot be revoked before expiry.
disposition: :attachment forces a download rather than inline display, and filename: controls the name the browser saves it as.
For genuinely private files, authorize before generating the URL. A signed URL proves nothing about who is asking; your controller has to.
Sample input:
invoice.pdf.url(expires_in: 15.minutes, disposition: :attachment)
Sample Output:
https://bucket.s3.amazonaws.com/abc123?X-Amz-Expires=900&X-Amz-Signature=...
Answer
# config/initializers/active_storage.rb
Rails.application.config.active_storage.service_urls_expire_in = 15.minutes
# Proxied through your app — revocable, but every byte goes through Rails
rails_blob_url(invoice.pdf, disposition: :attachment)
url_for(invoice.pdf)
# Direct to the storage service — fast, not revocable before expiry
invoice.pdf.url(expires_in: 15.minutes, disposition: :attachment)
# Control the downloaded filename
invoice.pdf.url(
expires_in: 5.minutes,
disposition: :attachment,
filename: ActiveStorage::Filename.new("invoice-#{invoice.number}.pdf")
)
# Variants of an image
user.avatar.variant(resize_to_limit: [200, 200]).processed.url(expires_in: 1.hour)
# Authorize FIRST — the signature says nothing about who is asking
class InvoicesController < ApplicationController
def download
invoice = current_account.invoices.find(params[:id])
redirect_to invoice.pdf.url(expires_in: 5.minutes, disposition: :attachment),
allow_other_host: true
end
end
Check viewARU - Brand Newsletter!
Newsletter to DEVs by DEVs - boost your Personal Brand & career! 🚀