概要
Carrierwaveを使用して外部サイトもしくはS3などから画像をダウンロードして保存する。
その際にヘッダーを指定する(今回はRefererのみ)
carrierwave側では画像のcontent_typeをpng/jpg/jpegに限定している。
試したけどうまくいかなかったパターン
open-uriでopenした画像を保存する
image_uri = URI.parse(uri) # uriを直接openするとセキュリティ的に問題があるためURI.parseする
file = image_uri.open("Referer" => "https://...")
user.avater = file
値が入らず断念。tmpファイルに書き出してから行えばうまくいけるかも。
2022年6月15日加筆
参考URL: https://docs.ruby-lang.org/ja/latest/library/open=2duri.html
値が入らなかったのはCarrierWaveがcontent_typeを拡張子から判断していたため。
open_uriで開いたファイルはTempfileクラスとして開かれるが、拡張子の命名規則がデフォルトではcontent_typeから類推してくれないことにより
バリデーションエラーが出てしまっていた。
保存するためにはダウンロードしたファイルのファイル名に.jpgなどの拡張子をつける必要があるので今回はCarrierWave::SanitizedFileクラスを利用する。
詳細に関してはこちらを参照ください。
https://github.com/carrierwaveuploader/carrierwave/blob/54f0ef9b1da48f9651f4428e78d19765ab7d3df2/lib/carrierwave/sanitized_file.rb
image_uri = URI.parse(uri) # uriを直接openするとセキュリティ的に問題があるためURI.parseする
res = OpenURI.open_uri(image_url, "Referer" => "https://...")
file = CarrierWave::SanitizedFile.new(tempfile: res, filename: res.base_uri.to_s, content_type: res.content_type)
user.avater = file
上手く行ったパターン
carrierwaveのremote_#{column}request_header=(header)とremote#{column}_url=(url)を使用する
carrierwaveのソースを読むと以下のようなメソッドが定義されているので利用する
columnの部分はモデルのmount_uploader
で指定したカラム名を使用する
今回はavaterカラムを例に使用
https://github.com/carrierwaveuploader/carrierwave/blob/229594fb2ac7cfa59586162c0b3fc3d0b5bab978/lib/carrierwave/mount.rb#L165
image_url = URI.parse(uri).to_s # URIクラスだと受け付けない
user.remote_avater_request_header = {"Referer" => "https://..."}
user.remote_avater_url = image_url
user.save!