この記事は、試行錯誤の経過です。まとめは、Rails2.1でSWFUploadを使うのまとめ - Paradigm Shift Designをご覧ください。
swfupload -
JavaScript & Flash Upload Library - Google Project Hosting
をRails 2.1に導入してみた記録。
最初、id:takihiroさんがまとめてくださっている、 Rails で SWFUpload を使う - takihiroの日記を読みつつ設定してみた。
コードはサンプルからコピーしてきたのでこんな感じ
<h1>複数ファイルのアップロード</h1> <script type="text/javascript"> var swfu; window.onload = function() { var settings = { flash_url : "/swfupload_f9.swf", upload_url: "<%= url_for :controller => 'contents', :action => 'upload' %>", file_size_limit : "100 MB", file_types : "*.jpg; *.jpeg", file_types_description : "Image Files", file_upload_limit : 100, file_queue_limit : 0, custom_settings : { progressTarget : "fsUploadProgress", cancelButtonId : "btnCancel" }, debug: true, // The event handler functions are defined in handlers.js file_queued_handler : fileQueued, file_queue_error_handler : fileQueueError, file_dialog_complete_handler : fileDialogComplete, upload_start_handler : uploadStart, upload_progress_handler : uploadProgress, upload_error_handler : uploadError, upload_success_handler : uploadSuccess, upload_complete_handler : uploadComplete, queue_complete_handler : queueComplete // Queue plugin event }; swfu = new SWFUpload(settings); }; </script> <input type="button" value="Upload file (Max 100 MB)" onclick="swfu.selectFiles()" style="font-size: 8pt;" /> <input id="btnCancel" type="button" value="Cancel All Uploads" onclick="swfu.cancelQueue();" disabled="disabled" style="font-size: 8pt;" /> <div class="flash" id="fsUploadProgress"> <!-- This is where the file progress gets shown. SWFUpload doesn't update the UI directly. The Handlers (in handlers.js) process the upload events and make the UI updates --> </div> <div id="uploadResult"></div>
でコントローラーのアクションメソッドは、
def upload p params end
てな感じ。もちろん、layoutのヘッダ部分に、
<%= javascript_include_tag 'prototype', 'swfupload/swfupload' %> <%= javascript_include_tag 'prototype', 'swfupload/swfupload.queue' %> <%= javascript_include_tag 'prototype', 'swfupload/handlers' %> <%= javascript_include_tag 'prototype', 'swfupload/fileprogress' %>
と、QueueとProgressを使うためのファイルをincludeする行を追加してあります。
この状態で、アップロードしてみると…SWFUploadのボタンを押すと
Error #2044: ハンドルされていない IOErrorEvent : text=Error #2038: ファイル I/O エラー。
とかいわれ、WEBrickのログには、
127.0.0.1 - - [13/Aug/2008:10:38:11 東京 (標準時)] "POST /contents/upload HTTP/1.1" 422 19900 - -> /contents/upload
とか表示される。
これはどうも、2.1?から標準になったCSRF対策のおかげらしい。
MuraTaka 速記メモ / 2008-06-13を参考に、コントローラーの冒頭に
protect_from_forgery :except => [:upload]
を追加する。ただ、上記サイトの方もおっしゃっているが、これで正しいのかは知りません。
で、よし、動くだろうと勇んでボタンを押したところ、また
Error #2044: ハンドルされていない IOErrorEvent : text=Error #2038: ファイル I/O エラー。
とか…orz
がしかし、WEBlickのログを読むに
127.0.0.1 - - [13/Aug/2008:11:45:32 東京 (標準時)] "POST /contents/upload HTTP/1.1" 500 661 - -> /contents/upload {"Filename"=>"IMG_0182.jpg", "action"=>"upload", "Upload"=>"Submit Query", "controller"=>"contents", "Filedata"=>#<File:C:/DOCUME~1/kent/LOCALS~1/Temp/CGI20080813-6848-bb3fd0-0>}
と、アクションメソッドは呼ばれている。なぜに500…とか思いつつ、色々探してみる。
には、
Flash has problems dealing with Rails sessions so a couple of quick fixes are needed. The first is to hack the sessions class. The fix can be found here.
とあって、Railsとやり取りするには,session classをhackする必要があるよ。と書いてある。お!と思って、やってみる*1。
caboo.seをinitializersの中にswfupload_fix.rbとして保存し、コントローラーの先頭に
session :cookie_only => false, :only => :create
と追記して、これで大丈夫だろう!とボタンを押すも…状況変わらず。
で、色々悩んだ挙句、上記サイトのサンプルコードを見ると、ブラウザに何か値を返している…
def upload p params render :text => "success!" end
とか、適当にやってみた。…動くじゃないか!
というわけで、swfupload_fix.rbとsessionを消してもきちんと動作しました。
結論としては、SWFUploadをRails2.1で動作させるためには、
- CSRFの対策をアップロード用のアクションメソッドで無効にする
- 必ず値を返すようにする
の二つが必要なようです。
まとめました。Rails2.1でSWFUploadを使うのまとめ - Paradigm Shift Design
*1:結論的には不要です