4

尝试open()远程图像时,一些返回为StringIO,另一些返回为File......我该如何强制File

data = open("http://graph.facebook.com/61700024/picture?type=square")
=> #<StringIO:0x007fd09b013948>

data = open("http://28.media.tumblr.com/avatar_7ef57cb42cb0_64.png")
=> #<StringIO:0x007fd098bf9490>

data = open("http://25.media.tumblr.com/avatar_279ec8ee3427_64.png")
=> #<File:/var/folders/_z/bb18gdw52ns0x5r8z9f2ncj40000gn/T/open-uri20120229-9190-mn52fu>

我正在使用 Paperclip 保存远程图像(存储在 S3 中),所以基本上想做:

user = User.new
user.avatar = open(url)
user.save
4

2 回答 2

13

Open-URI对对象有10KB限制StringIO,高于此限制,并将其存储为临时文件。

解决这个问题的一种方法是实际更改Open-URI用于对象限制的常量StringIO。您可以通过将常量设置为0;

OpenURI::Buffer.send :remove_const, 'StringMax' if OpenURI::Buffer.const_defined?('StringMax')
OpenURI::Buffer.const_set 'StringMax', 0

将其添加到您的初始化程序中,您应该一切顺利。

于 2012-02-29T15:18:36.337 回答
1

虽然 steigers 解决方案是一个简单的全方位解决方案,但我们中的一些人可能会被它的“讨厌的 hack”感觉以及它在全球范围内改变行为的方式所排斥。包括其他可能受益或依赖于 OpenURI 特性的 gem。办公室。您也可以使用上述方法,然后在完成后将常量重置为其原始值,并且由于 GIL,您也可能会摆脱这种肮脏(尽管一定要远离 jruby 和线程!) .

或者你可以做这样的事情,这基本上可以确保如果你得到一个流,它会被传送到一个临时文件:

def write_stream_to_a_temp_file(stream)
  ext = begin
    "."+MIME::Types[stream.meta["content-type"]].first.extensions.first
  rescue #In case meta data is not available
    #It seems sometimes the content-type is binary/octet-stream
    #In this case we should grab the original ext name.
    File.extname(stream.base_uri.path)
  end
  file = Tempfile.new ["temp", ext]
  begin
    file.binmode
    file.write stream.read
  ensure
    file.flush rescue nil
    file.close rescue nil
  end
  file
end

# and when you want to enforce that data must be a temp file then just...
data = write_stream_to_a_temp_file data unless data.is_a? Tempfile
于 2014-04-08T12:51:35.997 回答