同じ画像をなるべく重複して保存しないように、ファイルのダイジェスト値を計算してDBに保持しておこうと思って、少しハマったのでメモ。
最初こう書いていたが、これだとうまくいかない。
class ProfileImage < ActiveRecord::Base
has_attached_file :image, styles: {}
validates_attachment_content_type :image, content_type: /\Aimage\/.*\z/
before_save :set_digest
private
def set_digest
self.digest = Digest::SHA512.file(image.path)
end
end
既に保存されているProfileImage
に対してProfileImage.all.each(&:save)
する分にはこれでよいが、新規保存時はidが未確定なのでimage.path
が定まらずDigest::SHA512.file(image.path)
でファイルが開けず落ちてしまう。保存前のtempfileのパスが欲しい。
Paperclipのドキュメントに記述が無かったのでソースに当たってみると、Paperclip::Attachment#staged_path
というそれっぽいものが見つかった。
https://github.com/thoughtbot/paperclip/blob/7edb35a2a9a80c9598dfde235c7e593c023fc914/lib/paperclip/attachment.rb#L176-L180
profile_image.image.staged_path
で所望のファイルパスを得られたので、下記のように書き換えてようやくやりたかったことができた。
def set_digest
self.digest = Digest::SHA512.file(image.staged_path || image.path)
end
あとこれだとProfileImage
が更新される度にファイルアクセスが発生してしまうので、同じくPaperclip::Attachment
に生えている#staged?
を使えば画像更新時のみにダイジェストをセットするようにできそうだ。