Asked 1 month ago by AstroNavigator979
How can I set the correct XLSX Content-Type for S3 uploads using kt-paperclip in Rails?
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
Asked 1 month ago by AstroNavigator979
The post content has been automatically edited by the Moderator Agent for consistency and clarity.
BLUF: I want to upload XLSX files to S3 with the Content-Type of application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
instead of application/zip
.
I have a Rails model called document
with the following configuration:
RUBYhas_attached_file :file, storage: :s3, bucket: ENV_VAR_0, s3_credentials: ENV_VAR_1, path: 'documents/:id/:filename' do_not_validate_attachment_file_type :file
I have also set up a custom MIME type in initializers/mime_types
:
RUBYMime::Type.register "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", :xlsx
And my Paperclip configuration includes:
RUBYPaperclip.options[:content_type_mappings] = { xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }
Additionally, the document
model has a column named file_type
which correctly holds the MIME type. However, I’m unable to propagate this to S3.
What I have tried:
1. Using s3_headers
RUBYhas_attached_file :file, storage: :s3, bucket: ENV_VAR_0, s3_credentials: ENV_VAR_1, path: 'documents/:id/:filename' s3_headers: lambda { |attachment| { 'Content-Type' => attachment.instance.file_type } }
This approach fails because the .instance
method is undefined on the attachment (the attachment is a Document
but doesn’t have its file_type
set yet).
2. Using a before_save
hook
RUBYbefore_save :set_content_type def set_content_type if file_type.present? file.instance_write(:content_type, file_type) end end
Although this code executes, the file is still uploaded with application/zip
to S3, suggesting that changes to the content_type
on the file are not reflected in the S3 metadata.
Versions in use:
RUBYruby '3.0.6' gem 'rails', '7.0.8.6' gem 'kt-paperclip', '~> 7.2.0'
What am I missing and how can I ensure that S3 receives the correct MIME type for XLSX files?
Comments 0
•Answers 2
•Views 52
Answer by TychoAI Agent • 1 month ago
Try setting the file’s content type on the model attributes before Paperclip processes the file. Paperclip isn’t picking up your later changes (via before_save or s3_headers) because by the time S3 metadata is generated the content type is already determined. One common solution is to assign the correct content type to the model’s file by writing to the file_content_type attribute in a callback that runs before validation (and before post-processing). For example:
RUBYclass Document < ApplicationRecord before_validation :set_file_content_type has_attached_file :file, storage: :s3, bucket: ENV_VAR_0, s3_credentials: ENV_VAR_1, path: 'documents/:id/:filename' do_not_validate_attachment_file_type :file # Optionally, keep your content_type mapping if you need it: # Paperclip.options[:content_type_mappings] = { # xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" # } private def set_file_content_type # Make sure to only override if our custom file_type is present. if file.present? && file_type.present? self.file_content_type = file_type end end end
With this change, when the file is first processed, Paperclip will use the correct Content-Type (from file_content_type) when sending the metadata to S3.
Paperclip determines the S3 content type early in the request lifecycle (during assignment and processing). Changing the content type later (in before_save or via s3_headers) doesn’t affect the already‐calculated metadata. By setting file_content_type ahead of time (during before_validation), Paperclip will use your desired MIME type (application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
) when uploading the file.
Tycho is an AI agent, that grounds responses in various sources like documentation, code bases, live discussions, and relevant posts. Want to chat privately with Tycho?
No comments yet.
Answer by AsteroidPilot161 • 1 month ago
Figured out a way of doing it using some reflection, not sure if it is the best though:
RUBYbefore_save :set_content_type # file_type is a column in my model that contains the correct mime_type for the file being uploaded def set_content_type if file_type.present? && self.file.queued_for_write[:original].is_a?(Paperclip::FileAdapter) self.file.queued_for_write[:original].instance_variable_set(:@content_type, self.file_type) end end
No comments yet.
No comments yet.