Ruby open возвращает строку вместо файла? - PullRequest
3 голосов
/ 29 февраля 2012

При попытке 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>

Я используюСкрепка для сохранения удаленных изображений (которые хранятся в S3), поэтому в основном хочет сделать:

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

Ответы [ 2 ]

13 голосов
/ 29 февраля 2012

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

Добавьте это к своему инициализатору, и вам будет хорошо идти.

0 голосов
/ 08 апреля 2014

Несмотря на то, что решение Steigers является простым универсальным решением, некоторые из нас могут быть оттолкнуты его «неприятным хакерским» чувством и тем, как оно меняет поведение в глобальном масштабе. Включая другие драгоценные камни и такие, которые могут принести пользу или зависеть от этой функции OpenURI. Ofc. Вы также можете использовать вышеупомянутый подход, а затем, когда вы закончите, сбросить константу обратно к ее первоначальному значению, и из-за 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
...