我的一个邮件中有一行代码,用于添加带有用户姓氏和DoB的附件。类型错误";没有StringIO到String的隐式转换";有时出现在CCD_ 1方法中。
attachments["#{@user.last_name.downcase}-#{@user.date_of_birth.strftime('%d%m%y')}.jpeg"] = File.read(URI.parse(@user.profile_picture_url).open)
它在大多数情况下都能工作,但偶尔也会因为这个错误而失败。我正在使用carrierwave将文件上传到远程S3存储桶,如果这有区别的话。
编辑:
我在控制台上做了一些挖掘,坦率地说,这让我更加困惑!我有两个用户记录,都有通过carrierwave上传到S3的个人资料图片。如果我只是隔离File.read
方法,并使用两个记录进行尝试,一个有效,另一个无效。检查URI时,它们看起来几乎完全相同。
然而,我发现carrierwave支持读取文件的快捷方式,这解决了这个问题。这是更新后的代码:
attachments["#{@user.last_name.downcase}-#{@user.date_of_birth.strftime('%d%m%y')}.jpeg"] = @user.profile_picture.read
任何小于10kb
的内容都将作为StringIO
而不是File
打开。在文档中找不到实际的参考,所以来源如下:
StringMax = 10240
def <<(str)
@io << str
@size += str.length
# NOTE: once you pass 10kb mark, you get a tempfile.
# v
if StringIO === @io && StringMax < @size
require 'tempfile'
io = Tempfile.new('open-uri')
io.binmode
Meta.init io, @io if Meta === @io
io << @io.string
@io = io
end
end
https://github.com/ruby/ruby/blob/v3_2_0/lib/open-uri.rb#L398
让我们测试一下:
>> require "open-uri"
>> File.write("public/small.txt", "a"*10240)
=> 10240
>> URI.open("http://localhost:3000/small.txt").class
=> StringIO
>> File.write("public/large.txt", "a"*(10240+1))
=> 10241
>> URI.open("http://localhost:3000/large.txt").class
=> Tempfile
你可以File.read
和Tempfile
,但不能File.read
和StringIO
。
修复方法是在URI:上调用File.read
0
>> URI.parse("http://localhost:3000/small.txt").read.class
=> String
>> URI.parse("http://localhost:3000/large.txt").read.class
=> String
# also works
>> URI.open("http://localhost:3000/small.txt").read.class
=> String
https://rubyapi.org/3.2/o/openuri/openread#method-i-read