ドラッグアンドドロップで写真をアップロードしてDragonflyで扱いたい on rails
facebookやtwitterのように、ブラウザにドラッグアンドドロップすると自動でアップロードしてプレビュー表示というのをやりたかったので、色々と試してみました。
ドラッグアンドドロップでアップロード
この動作自体はjquery-html5-uploaderというプラグインを使ったら、えらく簡単にできました。
jquery-html5-uploaderのページに書いてある通り、プラグインをロードしてドロップ先のdiv要素とinput要素を用意するだけです。
アップロード先には、Dragonflyのphotoモデルを扱っているphotosコントローラを指定します。
こんな感じです。
$("#image-upload-area, #new_photo").html5Uploader({ name: "dd_file", postUrl: "<%= photos_url %>" });
アップロードされたファイルをDragonflyで扱う
ここではまりました。
photoモデルに紐付いたフォームでアップロードされるわけではないので、いつものように
@photo = Photo.new(params[:dd_file]) # dd_fileは上記javascriptのnameに指定した名前
とやっても、インスタンスを生成できません。
Dragonflyのドキュメントを読んでみると、tempfileオブジェクトからインスタンスを生成できると書いてあります。
最終的には下記の手順で無事写真を登録することができました。
def create if ( params[:dd_file] ) # Dragonflyアプリケーションを生成 app = Dragonfly[:photo] # params[:dd_file].tempfileでtempfileオブジェクトを取り出し、画像ファイルを生成 image_file = app.create(params[:dd_file].tempfile).to_file(params[:dd_file].original_filename) # photoモデルインスタンス生成 @photo = Photo.new # photo modelで定義したアクセッサ(photo_image)に画像ファイルをコピー @photo.photo_image = image_file end respond_to do |format| if @photo.save format.js format.html { redirect_to @photo, notice: 'Photo was successfully created.' } format.json { render json: @photo, status: :created, location: @photo } else format.html { render action: "new" } format.json { render json: @photo.errors, status: :unprocessable_entity } end end end
できてみると簡単なのですが、プレビュー動作も含めるとなんだかんだで2日もかかってしまいました。
[追記] CSRFトークンの追加
うまくいったと思ってよろこんでいたのですが、こんなログが出ていました。
WARNING: Can't verify CSRF token authenticity
jquery-html5-uploader経由だと、CSRFトークンが付かないので怒られているようです。
というわけで、jquery-thml5-uploader.jsに下記2行を追加することにしました。
var csrf_token = $("meta[name=csrf-token]").attr("content"); xmlHttpRequest.setRequestHeader("X-CSRF-Token", csrf_token);
追加した場所は、ファイルの後方で xmlHttpRequest.open("POST", settings.postUrl, true); の直後です。