/ Tags: RAILS-CODE / Categories: SOLUTIONS

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

Learn More

cdrrazan

Rajan Bhattarai

Full Stack Software Developer! 💻 🏡 Grad. Student, MCS. 🎓 Class of '23. GitKraken Ambassador 🇳🇵 2021/22. Works with Ruby / Rails. Photography when no coding. Also tweets a lot at TW / @cdrrazan!

Read More