passengerでrailsのpaperclipプラグイン使ってて今日ひとつ失敗した。
開発環境(mongrel)では問題なかったのに本番環境(mod_passenger)上でアップした画像が見えない。
理由は、
「画像はアプリの所有者でアップされるのにapacheの権限で見に行こうとするから。」
Phusion Passenger users guide
8.1. User switching (security)
Phusion Passenger solves this problem by implementing user switching. A Rails application is started as the owner of the file config/environment.rb, and a Rack application is started as the owner of the file config.ru.
passengerではUser switchingといって、rootやapacheではなく、railsではconfig/environment.rb、rackアプリではconfig.ruファイルの所有者でプロセスを立ち上げてくれるそうです。
(嫌ならPassengerDefaultUserディレクティブで他のユーザーに指定できる。)
当然、アップするファイルはそのユーザーで保存される。
しかし、アップした画像やページキャッシュなどの静的ファイルはApacheが直接見に行くのでpaperclipのアップ時のデフォルトのパーミッション(0600)だと見れない。(開発環境では個人のユーザーでmongrelを立ち上げるで問題が出なかった。)
対処方法は色々あるけど、やはりpaperclipが0644で保存してくれるのが一番じゃないだろうか。
ファイルの作成をそもそも0644にしようと思ってみてみると、paperclipでは標準ライブラリのtempfileでアップしたファイルを保存し、それをmvしてる。tempfileが0600で作るのでそのままだ。
例によってconfig/initializers以下で上書きする。
config/initializers/paperclip.rb:
module Paperclip
module Storage
module Filesystem
def flush_writes #:nodoc:
logger.info("[paperclip] Writing files for #{name}")
@queued_for_write.each do |style, file|
FileUtils.mkdir_p(File.dirname(path(style)))
logger.info("[paperclip] -> #{path(style)}")
FileUtils.mv(file.path, path(style))
FileUtils.chmod(0644, path(style))
file.close
end
@queued_for_write = {}
end
end
end
end
mvした後でchmodする。(10行目)
もっと局所的に書き換えたかったけどメソッドに切り出されてないのでここを変えた。
今回、本番デプロイ時にtagもbrunchも切ってないというミスを犯していたのでこのファイルだけ手でアップするという荒業に出た。反省・・・。