Webサービスを作って潰すのが趣味な人のブログ

とりあえず作ってから怒られよう

【Rails】Carrierwaveをデフォルト使用するとキャッシュ対応が面倒くさくなるのでそれに対応する2つの方法

f:id:vu2:20151130203518p:plain

 

Railsにファイルアップロード機構を搭載しようと思った場合一番最初に思い浮かぶgemがこいつ「Carrierwave」です

github.com

 

Carrierwaveのデフォルトの仕様では例えば「test.png」というファイルをアップするとそのままファイル名が使われるのでhttp://hoge.com/uploads/user/icon/1/test.pngみたいなURLになってしまいます。

別にこのURLでも問題ないと言えば問題ないのですが実は1つ大きな問題があります。

 

同名のファイルを更新アップロードした時にブラウザのキャッシュが消えない

ちょっと分かりづらいですね。

 

  1. 自分のアイコンとしてimage.pngというファイルをアップロードする
  2. アイコンを更新するためにimage.png(さっきと違う画像)をアップロードする
  3. アップロードはできているがブラウザにキャッシュが残るので画像が更新されない(よって、アップロードに失敗したとユーザーが勘違いして問い合わせてくる)

 

まあこれはcarrierwaveだけに限った問題では無いのですがこういう問題があります。

 

1.タイムスタンプをつける

例えば「"#{@user.icon_url}?#{@user.updated_at}"」とかやる方法ですね。

この方法は簡単に出来るのがメリットですが望まないタイミングでキャッシュを再読み込みさせてしまったり、それを避けるためには画像更新用のカラムを追加しなければいけなかったり、タイムスタンプを追加するロジックを加えなければいけなかったり……とかなり面倒くさいです。

 

2.ファイル名を自動でユニークな文字列に変更する

こっちが本命の方法ですが「そもそもアップロードされるファイルの名前をユニークなランダム文字列にすればいい」という考え方です。

 

公式にこれを実現したい場合のテストケースが載っていました。

github.com

 

gist0b6c99c8033bc0a8f907

 

ファイル名をUUIDで上書きしているだけなので特に説明もいらないと思います。

 

SecureRandom.uuidって?

本題とはずれるのですが、SecureRandom.uuidが何かわからない人もいると思うので一応説明しておきます。

誰かが一元管理していたり、重複をチェックする仕組みがないのに、世界でただ一つのIDを自由にいくらでも作って自分の機器を管理・識別するために使える--。そんな不思議なIDが「UUID」(universally unique identifier)です。日本語では「汎用一意識別子」などと訳しますが、実際にこちらを使うことはまずありません。

 UUIDは、なぜ勝手に作っても重複しないのでしょうか。それは、UUIDが機器の名前や時刻情報などを基に「十分大きなサイズかつランダムな数値」として生成される仕組みになっているからです。UUIDのサイズは16バイトで、256を16回掛けた数のバリエーションを作り出せます。これがどのくらいかというと、仮に毎秒数億個以上のスピードでUUIDを作ったとしても、人の一生どころか宇宙が誕生してから現在に至るまでの年月(約137億年)作り続けても重複などまずありえないほどです。実際のUUIDは、「UUID=6bffaf56-7af9-4d1a-a268-6195ca3c1de9」といった形式で表記されます。
参考:http://itpro.nikkeibp.co.jp/article/Keyword/20090206/324330/

 

UUIDは絶対にかぶらない=ユニークということで、特に気にせずに作りまくってもファイル名が毎回変更されるので安心です。

 

まとめ

UUIDってどういう仕組なのか気になっちゃいますね。プログラムを組む人間なら「擬似乱数」という言葉を聞いたことがあると思いますが、ほんとうの意味でランダムなものを生成するのは不可能とされています。それなのに一体どういう仕組なんだろう……

多分調べても僕じゃ理解できないのでやめておきますが技術の進歩ってすごいですね。そういえばmacアドレスとかも似たようなものと聞いたことがあるような気がします。

まあ今回の場合で言えば5文字のランダム文字列程度で十分だと思いますけどね。