GOL @Wiki

RoRでAjaxとthickboxを連携する

最終更新:

divadiva

- view
管理者のみ編集可


Ruby on Railsでフォーム内のボタンからAjaxを用いてアクションを呼び出して何らかの処理を実行し、その結果としてthickboxを使ったモーダルダイアログを表示する方法をまとめました。

図にするとこんな感じ。

thickboxはWebページをグレイアウトしてその上にダイアログウィンドウをを表示したい場合に利用できるものです。thickboxを動作させるにはまずjQueryをセットアップして利用可能とし、かつ、Rails標準のPrototype.jsとの競合を解決してやる必要があります。その方法はこのページを参照して解決しましょう。

そしてめでたく環境が整ったら、いよいよコーディングです。
まずフォームを表示するページですが、こんな感じです。
例) index.html.erb
<% form_remote_tag(:url => {:action => :アクションメソッド}... %>
 フォームの部品
<% end %>
このフォームタグは:actionだけを指定して:controllerを指定していませんので、index.html.erbが所属するコントローラを暗黙のうちに選択していることになります。また、from_remote_tagは通常のフォームサブミットではなく、Ajax通信を実行します。link_to_remoteとの違いは、通信時にたとえばテキスト入力ボックス等のフォームタグコンポーネントの情報もいっしょに送信することです。

さて、上記Ajax通信が実施されると、コントローラのアクションメソッドが呼び出されますので、必要な処理を実行させてください。
例) foobar_controller.rb
def アクションメソッド
  何らかの処理
end

さてここで問題なのが、「必要な処理」が終了したあとです。
だいたい、
  1. HTMLの破片を返す
  2. 何もしない
  3. Javascriptをクライアントに返して実行させる
のいずれかでしょう。モーダルダイアログを表示させるケースは3つ目に該当します。

アクションメソッド処理が完了すると、Railsは何らかのレンダリング処理をしようとします。ですのでレンダリング処理に関わるコードがなかったり、レンダリングするための素材(.html.erbや.js.rjsファイル)が存在しないと、エラーが発生します。

HTMLの破片を返すのは簡単です。これまで通りRailsの作法に従い「アクションメソッド名.html.erb」を準備しておけば、勝手にその内容を返してくれます。

また何もしない場合、アクションメソッドを下記のように記述します。
def アクションメソッド
  何らかの処理
  render :nothing => true
end

最後にちょっとわかりにくいのがJavascriptをクライアントに返して実行させる場合です。
まず最初にそのJavascriptの内容をアクションメソッドの中に書いてしまうか、あるいはRJSファイルを別途用意して、Railsに呼び出させるかの2通りがあります。

RJSファイルを利用する場合は「アクションメソッド名.js.rjs」ファイルを準備すればRailsが勝手に呼び出してくれます。RJSファイルの内容からJavascriptが生成されてクライアントに返信され、クライアントで実行してくれます。このとき、アクションメソッドに、
render :nothing => true
とか書いていると、RJSファイルが存在しても呼び出されないので注意して下さい。

そしてもう1つの方法、RJSファイルを利用せず、直接アクションメソッドに書いてしまう場合は、下記のようにします。
def アクションメソッド
  何らかの処理
  render :update do |page|
    Javascriptにさせる処理
  end
end

さて問題は、そもそものテーマであったthickboxによるダイアログ表示です。仮に「お知らせ」というタイトルで「public/aaa/inform.html」の内容を幅300px、高さ200pxのthickboxダイアログに表示させる場合、下記のように記述します。
def アクションメソッド
  何らかの処理
  render :update do |page|
    page << "tb_show('お知らせ', '/aaa/inform.html?height=200&width=300', '');"
  end
end

ちなみに、jGrowlを利用して通知ボックスを表示する場合は下記のようになります。(ただしPrototype.jsとjQuery.jsの競合を防ぐため、$をj$に置換している)
page << "j$.jGrowl('Hello world!');"
 または
page.call 'j$.jGrowl', 'Hello world!'
添付ファイル
記事メニュー
目安箱バナー