アップロードファイルの保存先

ファイルのアップロード機能をRailsで実現するのは意外と簡単で、HowtoUploadFiles in Ruby on Railsに詳細なチュートリアルがあるのですが、悩んでいるのはアップロードしたファイルをどこの保存するかなんです。チュートリアルや「RailsによるアジャイルWebアプリケーション開発」ではDBに保存する例があってそれにならってmediumblobのカラムに保存するよう作成してみたのですが、ちょっと気持ちが悪い。案の定、容量の大きなファイルをアップロードすると問題が発生します。

Mysql::Error: #08S01Got a packet bigger than ‘max_allowed_packet’

パケットサイズが大きすぎるとのこと。チュートリアルでもこの問題に関して触れていてmy.cnfのmax_allowed_packetパラメータを16Mとか増やせば解決できたのですが、開発環境ではこういったパラメータを勝手に変えることはできても実際のホスティング環境ではパラメータの変更は許されていません。

もとより、ある程度の制限は必要なのですが1M(show variablesコマンドで確認)はちょっと寂しいのでもう少しなんとかならないかといくつか試してみました。まず、アップロードしたファイルを圧縮してしまうという手。

blob_col = Zlib::Deflate.deflate(uploadfile.read,Zlib::BEST_COMPRESS)

今回考えているのはjpeg等の画像ファイルで殆どサイズが変わらず、これは効果なし。

次は、max_allowed_packetの値を動的に変えてしまおうと、

def before_save
  ActiveRecord::Base.connection.execute('set session max_allowed_packet=16000000')
  :
end

としてみましたがこれも効果なし。実際のsave()時には別のsessionとなるのでしょうか?

この時点で遺憾ながら諦めました。問題をうまく回避できなかったこともありますが、実際問題としてDBに保存するのは少し気持ちが悪いです。仮にmax_allowed_packetの値を動的に変更することができたとしてもMySQL以外のDBを選択するという自由がなくなってしまうわけでここは素直にファイルに保存することにしました。また、先のチュートリアルの中でも

In the above, the file contents gets inserted into the hash as a string – ie. it’s read to memory. Is that the best we can do? Can we not pass a file-reference or similar and via that get the file contents streamed from the filesystem to the DB?

と言っています。

この記事のトラックバックURL:

http://hippos-lab.com/blog/trackback/63

返信