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あり、それを超えると一時ファイルとして保存されます。

これを乗り越える1つの方法は、オブジェクト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

シュタイガーズのソリューションはシンプルなオールラウンドソリューションですが、私たちの中には、その「厄介なハック」の感覚と、それがグローバルに動作を変更する方法に反発する人もいるかもしれません。OpenURIのこの機能に利益をもたらす、または依存する可能性のある他の宝石などを含みます。多くの場合。上記のアプローチを使用することもできます。完了したら、定数を元の値にリセットします。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 に答える