Rails2.1でSWFUploadを使うのまとめ
せっかくなので、まとめておきます。
利用しているものは、次のようになっています。
- Ruby 1.8.7
- Rails 2.1
- SWFUpload 2.1.0
- restful_authentication
Rails2.1上でのSWFUploadとrestful_authenticationの組み合わせは、色々設定しないとちゃんと動いてくれないようです。
まず、rails2.1で使う場合の問題点を列挙します。
- CSRF対策がデフォルトで入っている
- Flashに対してセッションを送れない
- session_idに改行が入るようになった
- 値を返さないと、I/Oエラーになる
というわけで、まず、
#243653 - Pastie
上記URLのスクリプトを、initializersディレクトリにswfupload_fix.rbのような名前で保存します。これは、Session周りのハックをするスクリプトです。
アップロード対象とするコントローラーの先頭に、CSRF対策を無効にして、sessionでクッキーを使わないようにする2行を挿入します。
私のプログラムでは、contentsコントローラーのuploadアクションメソッドをSWFUploadのupload_pathに指定していますので、次のようになります。
session :cookie_only => false, :only => :upload protect_from_forgery :except => [:upload]
次に、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を使わない場合は、swfuploadだけでいいです。
ビューは次のようにします。
<script type="text/javascript"> //アップロード成功時のハンドラー function myUploadSuccess(file, serverData) { try { eval("var result=" + serverData); var progress = new FileProgress(file, this.customSettings.progressTarget); progress.setComplete(); if(result.error){ progress.setStatus(result.error); }else{ var content = result.content; progress.setStatus("Complete."); } progress.toggleCancel(false); } catch (ex) { this.debug(ex); } }; //SWFUploadの設定 var swfu; window.onload = function() { var settings = { flash_url : "/swfupload_f9.swf", upload_url: "<%= url_for :controller => 'contents', :action => 'upload' %>?_AppName_session=<%= u(session.session_id) %>", 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: false, // 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 : myUploadSuccess, upload_complete_handler : uploadComplete, queue_complete_handler : queueComplete // Queue plugin event }; swfu = new SWFUpload(settings); }; </script> <!-- アップローダーの設置 --> <div id="uploader" style="float: left; width=500px"> <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> </div>
アップロードが成功したとき以外は、handlers.jsで提供されているハンドラを使っています。ここで重要なのは、upload_pathの記述です。
upload_url: "<%= url_for :controller => 'contents', :action => 'upload' %>?_AppName_session=<%= u(session.session_id) %>"
upload_urlの引数として、セッションIDを渡します。引数名は、_AppName_sessionのAppNameをアプリケーション名にするか、自分で設定したものを記述します。またRails2.1ではsession.session_idに改行が入ってしまいますので、uヘルパーを使ってURLエンコードしてください。
後は、コントローラーのアクションメソッドを次のように記述します。
def upload uploaded = params[:Filedata] render :text => {"message", "Uploaded!"}.to_json end
これで、Rails2.1上で、restful_authenticationとSWFUploadが正しく動作します。
参考サイト
- 404 Not Found
- Alistair Holt - Designer & Developer
- #243653 - Pastie
- Rails で SWFUpload を使う - takihiroの日記
試行錯誤の痕