Refile
昨日知ったのですが、Refileというファイルアップロード用のgemがとてもナウい感じです。
id:willnetさんとかが記事にしてました。
ざっと触ってみて、そのうち使えそうだったのでメモ。
作ったサンプル
Readmeほぼそのまま
基本
普通のアップロード機能を実装しました。
サムネイル表示忘れましたが、ヘルパが用意されています。
Sinatra製の画像サーバが内蔵されていて、そちらで"表示時の"リサイズ、クリッピング等に対応します。Rails利用時には自動的にマウントされるようです。
利用する場合はフロントキャッシュ等と組み合わせることが必須になりますが、とても便利ですね。見たところキャッシュ用のHTTPヘッダもきちんと使用されているようですので、リバースプロキシとしてnginxを使っているならとても簡単に設定できることでしょう。
あとはCloudFrontのカスタムオリジンあたりが簡単でしょう。
S3への保存
今回保存先をS3にしたのでそちらにアップロードされました。
Refile.store = Refile::S3.new(prefix: "store", **aws)
確認画面を実装してみる
公式の方法はわからなかったので、コードを読んで適当に実装しました。適当なのでこれではうまくいかないケースもあるかもです。
<% if f.object.confirming? %>
<div class="field">
<%= f.label :name %><br>
<%= f.object.name %>
<%= f.hidden_field :name %>
</div>
<% if f.object.file.present? %>
<div class="field">
<%= f.hidden_field :file, value: f.object.file_attacher.data.to_json %>
<%= image_tag attachment_url(f.object, :file, :fill, 200, 200) %>
</div>
<% end %>
file_attacher
の所は現在のmasterではfile.attacher
になるみたいです。
これで無事確認画面で画像のプレビューができました。
なお、レコードを保存する前、アップロードしただけの状態のファイルはcacheと呼ばれます。
Refile.cache = Refile::S3.new(prefix: "cache", **aws)
Refile.store = Refile::S3.new(prefix: "store", **aws)
今回、上記のようにして、実際の保存先及びcacheのどちらもS3に設定したので、cacheもS3上にあります。
これの何が嬉しいかというと、確認画面を実装した場合に、保存先がローカルストレージだと複数台のアプリサーバで構築しているシステムの場合に、確認画面と保存で別々のサーバに割り振られ、うまくいかなくなる可能性があります。
carrierwaveの場合、今日現在普通にインストールできるバージョン(0.10.0)ではこのようなケースでうまく行かないのですが、Refileの場合は現在バージョン(0.5.5)でも問題なくS3を利用した場合でも確認画面を実装できました。
ファイル削除に対応
Readmeの通りなのですが、先に実装した確認画面で、削除にチェックを入れた場合に表示したくなかったので、次のようにRefile::Attacher#remove?
を使ってみました。例によってドキュメントにないので正しい方法かはわかりません。
<% if f.object.confirming? %>
<div class="field">
<%= f.label :name %><br>
<%= f.object.name %>
<%= f.hidden_field :name %>
</div>
<% if f.object.file.present? %>
<% unless f.object.file_attacher.remove? %>
<div class="field">
<%= f.hidden_field :file, value: f.object.file_attacher.data.to_json %>
<%= image_tag attachment_url(f.object, :file, :fill, 200, 200) %>
</div>
<% end %>
<% end %>
<%= f.hidden_field :remove_file %>
ダイレクトアップロード
ドキュメントまま。
RefileのJavaScriptライブラリを使うことで、ヘルパにdirect: true
オプションを追加するだけで、ファイルを選択されたら直接アップロードを開始できるようになります。ユーザーの待ち時間を減らすことができますね。
コントローラやモデルへの変更は一切不要です。
<%= f.attachment_field :file, direct: true %>
Presigned uploads(S3への署名付き URL を使用したオブジェクトのアップロード)
ヘルパにpresigned: true
オプションを追加するだけで、サーバを介さずに、ブラウザから直接S3へアップロードできるようになります。
それも、コントローラやモデルへの変更は一切不要、通常のアップロードと同じように扱えるのが素晴らしいです。
署名付き URL を使用したオブジェクトのアップロードについてはこちらを。
また、この機能は先のダイレクトアップロード機能と併用することもでき、
<%= f.attachment_field :file, direct: true, presigned: true %>
このようにすると、ファイルを選択した時点ですぐにS3に直接アップロードされます。
仕組みとしては、ビューのレンダリングの際に、S3の署名付きURLを発行してdata属性にセットしておき、onchangeハンドラで使用する、というもののようです。なるほど、勉強になります。
ファイル種類の検証
拡張子やMIMEタイプ、MIMEタイプのグループ(デフォルトで提供されるものほか、独自に定義可能)の制限が簡単にできます。
複数ファイルのアップロード
input type="file" multiple
を使って複数選択したファイルを一括アップロードでき、それを一対多で保存できます。
この機能も、ダイレクトアップロード、署名付きURLでのアップロードにも対応しており、以下のようにして利用できます。
<%= f.attachment_field :images_files, multiple: true, direct: true, presigned: true %>
※2015.7.6現在の最新リリース(0.5.5)には含まれていないので、使いたいならgithubからインストールする。
gem 'refile', require: 'refile/rails', github: 'refile/refile'