Rails adds the ability to pass the expires_at option to ActiveStorage::Blog#signed_id

railsOctober 20, 2023Dotby Alkesh Ghorpade

Rails adds the ability to pass the expires_at option to ActiveStorage::Blob#signed_id. The signed_id attribute of an ActiveStorage Blob is a unique identifier for the blob that is signed with a secret key. It makes it safe to share the signed ID with the client without worrying about unauthorized access to the blob.

Signed IDs can be used to:

  • Generate URLs for downloading or streaming blobs.

  • Generate pre-signed URLs for blobs that the client can use to upload files directly to the storage service.

  • Identify blobs that the client has uploaded.

Till Rails 7.1

ActiveStorage URLs are permanent by default, but you can use the expires_in option to create expiring URLs. This can be useful for sharing sensitive files or files you don't want publicly accessible forever.

Till Rails 7.1, to create a signed ID for ActiveStorage blob, you need to use the signed_id method as below:

class User < ApplicationRecord
  has_one_attached :unique_identification_document
end

user.unique_identification_document.attach(
  io: File.open('path/to/file'),
  file_name: 'file_name.png',
  content_type: 'image/png'
)

# Create a signed expiring URL
signed_id = user.unique_identification_document.signed_id(expires_in: 1.minute)
=> "eyJfcmFpbHMiOnsiZGF0YSI6MSwiZXhwIjoiMjAyMy0xMC0yMFQwOTo0MTo1Ny4yMTZaIiwicHVyIjoiYmxvYl9pZCJ9fQ==--c34f0f13f53411dbd55bbf14184d8d1d122cef4b"

blog = ActiveStorage::Blob.find_signed(signed_id)
=> #<ActiveStorage::Blob:0x000000010db2bb38
 id: 1,
 key: "io9fm1hjblzq5zsvge2hp5si3oev",
 filename: "file_name.png",
 content_type: "image/png",
 ....

# After 1 minute
blog = ActiveStorage::Blob.find_signed(signed_id)
=> nil

After Rails 7.1

The recent changes in Rails allow you to pass the expires_at option.

When using the expires_in option to generate an expiring URL, the URL will change each time it is generated. This means the browser cannot cache the URL, and the user will have to download the file each time they access it.

In contrast, when using the expires_at option, the URL will remain the same until it expires. This means that the browser can cache the URL, and the user will not have to download the file again if they access it within the cache window.

user.unique_identification_document.signed_id(expires_at: 1.minute)

rails_blob_path(
  user.unique_identification_document,
  disposition: "attachment",
  expires_at: 1.hour.from_now.beginning_of_hour
)

<%= image_tag rails_blob_path(
      user.unique_identification_document.variant(resize: "100x100"), 
      expires_at: 1.hour.from_now.beginning_of_hour
    )
%>

To know more about this feature, please refer to this PR.

Closing Remark

Could your team use some help with topics like this and others covered by ShakaCode's blog and open source? We specialize in optimizing Rails applications, especially those with advanced JavaScript frontends, like React. We can also help you optimize your CI processes with lower costs and faster, more reliable tests. Scraping web data and lowering infrastructure costs are two other areas of specialization. Feel free to reach out to ShakaCode's CEO, Justin Gordon, at justin@shakacode.com or schedule an appointment to discuss how ShakaCode can help your project!
Are you looking for a software development partner who can
develop modern, high-performance web apps and sites?
See what we've doneArrow right