我正在尝试使用回形针 4.1.1 将 CSV 文件附加到 Rails3 模型,但我无法将 S3 报告的内容类型设置为
text/csv
(相反,我得到 text/plain
)。当我随后从 S3 下载文件时,扩展名将被更改以匹配内容类型,而不是保留原始扩展名(因此 test.csv 将下载为 test.txt)。
据我所知,当您上传文件时,FileAdapter 将在创建时缓存内容类型,并使用 ContentTypeDetector (调用
file -b --mime filename
)确定的任何值。不幸的是,CSV 文件返回 text/plain
,这是有道理的,因为你如何真正区分这一点?尝试使用 attachment.instance_write(:content_type, 'text/csv')
设置内容类型只会设置模型中的值,不会影响写入 S3 的内容。
FileAdapter 的 content_type 在这里初始化:https://github.com/thoughtbot/paperclip/blob/v4.0/lib/paperclip/io_adapters/file_adapter.rb#L14
创建 io_adapter 的调用: https://github.com/thoughtbot/paperclip/blob/v4.0/lib/paperclip/attachment.rb#L98
我这里确实有一个通用上传(所以我无法在
has_attached_file
中的S3标头定义中对内容类型进行硬编码),而且我真的不想要内容类型欺骗保护。有什么想法/建议吗?我不想降级到 3.5,因为这意味着只是延迟痛苦,但如果这是唯一的方法,我会接受它......
如果您正在使用
fog
那么您可以执行以下操作:
has_attached_file :report,
fog_file: lambda { |attachment|
{
content_type: 'text/csv',
content_disposition: "attachment; filename=#{attachment.original_filename}",
}
}
如果您使用 Amazon S3 作为存储提供商,那么类似这样的操作应该有效:
has_attached_file :report
s3_headers: lambda { |attachment|
{
'Content-Type' => 'text/csv',
'Content-Disposition' => "attachment; filename=#{attachment.original_filename}",
}
}
最近遇到了这个问题,后处理和 lambda 都不起作用,所以做了一个解决办法。与其他观察结果相同,调用 s3 lambda 标头时附件的值为空。
attr_accessor :tmp_content_type, :tmp_file_name
def file=(f)
set_tmp_values(f.path)
file.assign(f)
end
def set_tmp_values(file_path)
self.tmp_file_name = File.basename(file_path)
self.tmp_content_type = MIME::Types.type_for(file_path).first.content_type
end
:s3_headers => lambda { |attachment|
{
'Content-Type' => attachment.tmp_content_type,
"Content-Disposition" => "attachment; filename=\"# {attachment.tmp_file_name}\""
}
}
我正在将 Paperclip 6.1.0 与 Rails 5.2.3、Ruby 2.6.6 一起使用,这个答案使用了 James Euangel 在现有答案中提出的相同想法,但它更通用,并使用猴子修补。
我将在使用
Paperclip::Attachment
作为文件附件的模型上定义 attr_accessors,并使用它们来设置传递给 s3_headers
宏的 has_attached_file
选项中的值。
# app/models/concerns/paperclip_attributes_maker.rb
# This concern defines attr_accessors for the paperclip attachment attributes of the ActiveRecord model
module PaperclipAttributesMaker
extend ActiveSupport::Concern
def self.included
base.class_eval do
base::PAPERCLIP_ATTACHMENT_ATTRS.each do |attachment_attr|
attr_accessor "paperclip_#{attachment_attr}_content_type"
attr_accessor "paperclip_#{attachment_attr}_filename"
end
end
end
end
现在,我们需要对 Paperclip::HasAttachaedFile 类中定义的附件设置方法进行猴子修补:
# app/initializers/patch_paperclip_has_attached_file.rb
# it patches paperclip/has_attached_file.rb
module Paperclip
class HasAttachedFile
def define_setter
name = @name
@klass.send :define_method, "#{@name}=" do |file|
content_type = (file.content_type || MIME::Types.type_for(file.path).first.content_type) rescue nil
instance_variable_set("@paperclip_#{name}_content_type", content_type)
instance_variable_set("@paperclip_#{name}_filename", (file.original_filename rescue nil))
send(name).assign(file)
end
end
end
end
最后,我们声明 Paperclip 附件(我的意思是我们在 ActiveRecord 模型中获得了多少个附件):
class StudentAttachment < ApplicationRecord
PAPERCLIP_ATTACHMENT_ATTRS = [:attachment1, :attachment2]
include PaperclipAttributesMaker # should be included after definition of PAPERCLIP_ATTACHMENT_ATTRS
#...other code
has_attached_file :attachment1, { # other options here
s3_headers: lambda { |attachment|
{
'Content-Type' => attachment.paperclip_attachment1_content_type,
"Content-Disposition" => "attachment; filename=\"#{attachment.paperclip_attachment1_filename}\""}}
}
has_attached_file :attachment2, { # other options here
s3_headers: lambda { |attachment|
{
'Content-Type' => attachment.paperclip_attachment2_content_type,
"Content-Disposition" => "attachment; filename=\"#{attachment.paperclip_attachment2_filename}\""}}
}
end