paperclip の保存ディレクトリ名あるいはファイル名をid連番ではなく、MD5とかSHA1のハッシュ値にするメモ

画像を扱う際のrailsプラグインpaperclip
GitHub - thoughtbot/paperclip: Easy file attachment management for ActiveRecord

基本的な使い方は、githubとか紹介ページを参照してもらうとして、
ここでは画像保存のディレクトリ名あるいはファイル名をid連番ではなく、
推測しにくい値にする方法をメモしておきます

前置き

まず、デフォルトの設定だと保存pathは、

:rails_root/public/system/:attachment/:id/:style/:filename

らしいです。

なので、例えばimageモデルで、

  has_attached_file :image,
    :styles => {
      :thumb   => "100x100#",
      :mini   => "30x30#"
    }

のようにしていたとすると、
hoge.jpgをアップロードして保存した際には、各画像は下記のpathで保存されます


public/system/images/1/original/hoge.jpg
public/system/images/1/thumb/hoge.jpg
public/system/images/1/mini/hoge.jpg


上のようにデフォルトのまま使わないにしても、
画像ごとにユニークなpathを作るために、
ディレクトリ名かファイル名のどこかにidを入れる可能性は高いかなと思います
例えば、

  has_attached_file :image,
    :styles => {
      :thumb   => "100x100#",
      :mini   => "30x30#"
    },
    :path => ":rails_root/public/sys_img/:id/:style.:extension",
    :url  => "#{ActionController::Base.relative_url_root}/sys_img/:id/:style.:extension"


public/sys_img/1/original.jpg
public/sys_img/1/thumb.jpg
public/sys_img/1/mini.jpg


ただこのような連番idでは、URLのid部分を変更して直アクセスすることで、
他の画像を見ることができるということを、ユーザに想像される可能性は高いです


別に、見られて問題ない画像しかなければ良いですが、
例えば、予め画像データだけはアップロードしてあるが、
まだ、サイトにはリンクや埋め込みをしておらず、
それをするまでは画像を見られたくない場合において、連番idは危険度が高いと思います


確実な解決方法としては、
「画像の公開日付みたいなカラムを持ち、
画像をユーザが直接アクセスできない場所に保存して、
コントローラ経由で画像を出力する」、ことだとは思いますが、
そこまでしなくても、「連番idをやめて、推測しにくいpathに画像を保存する」
ことができればそれで良い場合もあると思います

で、どうするかというと

で、前置きが長くなっちゃいましたが、どうするかというと、
config/initializers/ の下に適当なファイル名(例えば、paperclip.rb)でファイルを作って、その中に次のように記述します

Paperclip::Attachment.interpolations[:id_sha1] = proc do |attachment, style|
  Digest::SHA1.hexdigest(attachment.instance.id.to_s)
end

で、モデルでは定義した :id_sha1 を使って、

  has_attached_file :image,
    :styles => {
      :thumb   => "100x100#",
      :mini   => "30x30#"
    },
    :path => ":rails_root/public/sys_img/:id_sha1/:style.:extension",
    :url  => "#{ActionController::Base.relative_url_root}/sys_img/:id_sha1/:style.:extension"

とすることで、idのSHA1ハッシュ値ディレクトリ名にすることができます


public/sys_img/356a192b7913b04c54574d18c28d46e6395428ab/original.jpg
public/sys_img/356a192b7913b04c54574d18c28d46e6395428ab/thumb.jpg
public/sys_img/356a192b7913b04c54574d18c28d46e6395428ab/mini.jpg

もちろんURLも:urlに書いておけばちゃんと作ってくれます

# viewファイルにて
image.image.url(:mini)  # /sys_img/356a192b7913b04c54574d18c28d46e6395428ab/mini.jpg


画像の created_at とか secret_key を混ぜれば、ほぼ推測されることはないかと思います
config/initializers/paperclip.rb

Paperclip::Attachment.interpolations[:mix_sha1] = proc do |attachment, style|
  secret_key = "paperclip_test's secret key string"
  Digest::SHA1.hexdigest("#{attachment.instance.id}#{attachment.instance.created_at.to_i}#{secret_key}")
end


参考:http://d.hatena.ne.jp/hichiriki/20081130