Ruby open возвращает строку вместо файла?
При попытке 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
2 ответа
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
Добавьте это к своему инициализатору, и вы должны быть готовы.
В то время как решение 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