Active Storage 结合 Amazon S3 上传异常:文件以Key而非原文件名存储
Hey Andrew, let’s break down why this is happening and how to fix it—this is actually expected default behavior from Active Storage, not a bug in Rails 5 or misconfiguration on Amazon S3.
Why Files Are Stored with Random Keys
Active Storage uses unique, random keys (like 5YE1aJQuFYyWNr6BSHxhQ48t) instead of original filenames for two key reasons:
- Prevent filename conflicts: If two users upload files with the same name (e.g.,
myfile.zip), the later upload won’t overwrite the earlier one. - Boost security: It stops attackers from guessing filenames to access sensitive files they shouldn’t have permission to view.
Solution 1: Customize Storage Keys to Preserve Original Filenames
If you want the actual filename to appear in your S3 bucket (while still avoiding conflicts), you can define a custom key generator in your config/storage.yml file.
Here’s a sample S3 configuration with a custom key structure:
s3: service: S3 access_key_id: <%= Rails.application.credentials.dig(:aws, :access_key_id) %> secret_access_key: <%= Rails.application.credentials.dig(:aws, :secret_access_key) %> region: us-east-1 bucket: your-bucket-name # Custom key that includes a random UUID + original filename to avoid conflicts key: <%= ->(blob) { "uploads/#{SecureRandom.uuid}/#{blob.filename}" } %>
This will store files in S3 with paths like uploads/abc123xyz/myfile.zip—the random UUID ensures uniqueness, while the original filename is preserved at the end.
You can tweak the structure further (e.g., organize files by user ID):
key: <%= ->(blob) { "users/#{blob.record.id}/#{SecureRandom.uuid}/#{blob.filename}" } %>
Note: Active Storage’s filename attribute automatically sanitizes invalid characters (like spaces or special symbols) to comply with S3’s naming rules.
Solution 2: Keep Random Storage Keys, Show Original Filename on Download
If you don’t care about the filename in S3 but want users to download files with their original names, you don’t need to change storage settings. Instead, adjust your controller to set the download filename.
Here’s a sample controller action:
def download blob = ActiveStorage::Blob.find(params[:id]) send_data blob.download, filename: blob.filename.to_s, type: blob.content_type, disposition: "attachment" end
When users hit this endpoint, their browser will receive the file with its original name (e.g., myfile.zip) even though it’s stored as a random key in S3.
Quick Sanity Checks
- Confirm your
storage.ymlis linked correctly in your environment config (e.g.,config/environments/production.rb):config.active_storage.service = :s3 - Verify your S3 bucket has proper write permissions for Active Storage (this doesn’t affect filename handling, but ensures uploads work at all).
内容的提问来源于stack exchange,提问作者Drew Potter

