yamazのRails日記 このページをアンテナに追加 RSSフィード

2006-09-08RailsでAjaxっぽく画面遷移なしでファイルアップロードしたい! このエントリーを含むブックマーク

RailsAjaxっぽく画面遷移なしでファイルアップロードしたい!」

と思っていたところ,こんなページが見つかった.

http://sean.treadway.info/demo/upload/

であれこれ解析していたところ,のりおさん@RailsChatからナイスなモノを教えてもらった(同じサイトなのに気づかなかった).

http://sean.treadway.info/svn/plugins/responds_to_parent/


(2010/12/10 追記 配布元が変わったようです)

https://github.com/markcatley/responds_to_parent


結果として画面遷移なしでファイルのアップロードができるようになった.

ついでにざっと解析したので使い方と解析結果を備忘録もかねて書いておく(最近このパターンばっかし).

使い方

1. respond_to_parent pluginをインストール

% ruby script/plugin install https://github.com/markcatley/responds_to_parent.git

2. view(main.rhtml)はこんなの

      <div id="stuff">Here is some stuff</div>
      <form target="frame" action="form_action" enctype="multipart/form-data" method="post">
        <input type="file" name="uploaded_file"/>
        <input type="submit"/>
      </form>
      <iframe id='frame' name="frame"></iframe> <!-- ← Upload用ダミーIframe -->
   

3. contoroller(のメイン部分)はこんなの

 def main
 end
 def form_action
    # Do stuff with params[:uploaded_file]
    file = params[:uploaded_file]
    File.open("/tmp/#{file.original_filename}","wb") do |f|
      f.write(file.read)
    end
    responds_to_parent do
      render :update do |page|
        page << "alert($('stuff').innerHTML)"
      end
    end
  end

これで/tmpにファイルが遷移なしでアップロードされます.

今回RJSでprototype.js使ってますが,本来はprototype.jsは必須ではないです.


仕組み

JavaScriptではセキュリティ上、直接のファイルアップロードはできません

まずJavaScript単体ではファイルのアップロードはできません.

AjaxはFormデータをシリアライズしてサーバにリクエストを投げていますが,

ファイルのアップロードができちゃうとJavaScriptPCのファイルを

のぞけると言うことになっちゃうので,セキュリティ上できません.

formのtarget属性を使ってiframe内でactionのリクエスト結果を表示する

formタグにはtarget属性というのがあって,リクエストを処理するブラウザの

ウインドウ名が指定できます.Aタグのtarget="_new"とかで新しいウィンドウを

開くみたいなノリだ.またそのターゲットはname指定されたiframeでもOKなので,

iframe内で処理をすることによって遷移なしのファイルアップロードが実現できている.

今回の例では'frame'というname属性をもったダミーIframeタグを準備しているので,

これがブラウザ上で見えて嫌な人はstyle="display:none;"などで隠すとよい.


iframe側では親Windowの情報を取得できる.

またiframe側では親Window(Iframeタグが書かれたページ)の情報も取得,JSによるDOM書き換えができる.


それをサポートしてくれるのがresponds_to_parentで、ブロック内でrender :updateすると呼び出し側のページに対して動作するようなJSコードをIframe内に展開&評価実行する.これによってアップロードした後にページを書き換えたいなどもOKになる.あとブロックを持つことでRJSも書ける.

はまりどころ

付属のREADMEのFORMタグにはenctype="multipart/form-data" method="post"がついてないのでつけましょう.


使ってみた感想

これで画面遷移なしでファイルのアップロードができるようになった.

これを利用すればファイルをアップロードした後にその画像をいきなり表示とかも可能なので,

かっちょいいページをゼヒ作っていきたい.

(おしまい)

yamaz的日常

はてな近藤さんがアメリカ行った理由ってアメリカ出張で「東京での通勤イヤイヤ病」にかかったからだと思う(だいたひかる調).

9/10追記

上記responds_to_parent pluginですが,ブラウザの不具合でJavaScriptを含むHTML

(正確には</script>を含むHTML)を親ページにレンダリングしようとすると

うまく動かないようだったので,パッチを送って採用してもらいました.

万一すでにインストールした人がいたら再インストールするといいです.

KathreenKathreen2011/09/08 12:37You're a real deep thikner. Thanks for sharing.

glviiiwudmuglviiiwudmu2011/09/09 00:0048VA3A <a href="http://uchnwlgzldpe.com/">uchnwlgzldpe</a>

grtcrfqugrtcrfqu2011/09/09 21:25FGTAmK , [url=http://hnvoauohhlhf.com/]hnvoauohhlhf[/url], [link=http://dbbkalfnydpt.com/]dbbkalfnydpt[/link], http://pwlaogiwsejv.com/

ednkvcowipwednkvcowipw2011/09/10 19:28EYACJZ <a href="http://cxcthullvckd.com/">cxcthullvckd</a>

rwnwsorwnwso2011/09/12 19:36dYvsBV , [url=http://eshrsonsdhpq.com/]eshrsonsdhpq[/url], [link=http://habmzmsjzeql.com/]habmzmsjzeql[/link], http://rpcpiaehihqt.com/