RailsでJSON-RPC
http://blog.masuidrive.jp/articles/2006/03/01/newrails で、Rails1.1からObjectにto_jsonメソッドが追加されるっていうんで、もしかしてJSON-RPCが特別な仕組み無しで実現できちゃうんじゃないの?と思ってたら、一部できちゃった、というお話。
ここで想定しているのは、パラメータを幾つか渡してサーバから一覧を取得するとか、そういう場合。複雑な構造を持つオブジェクトをJSONでサーバに送って更新、とかそういう場合はもっと別な仕組みがいるはず。
まずサーバサイド。例えば書籍一覧を書名で絞り込みたい場合
class BookController < ActionController::Base def json_find_books render_text Book.find_by_book_name( params[:book_name] ).to_json end end
検索結果をto_jsonメソッドでjson形式の文字列に変換する。これでサーバサイドは準備OK!
あ、余計なattributeを送らないようにHashのArrayに変換したほうが良いかも。
次はクライアントサイド。全部書くと大変なので重要なとこだけ書きます。まずは呼び出すところ。prototype.jsのAjax.Requestを使います。
var queryParamString = $H(queryParams).toQueryString(); var options = { method: "get", parameters: queryParamString, asynchronous: true, requestHeaders: ["Content-type", "text/plain"], onComplete: this.responseComplete.bind(this) }; new Ajax.Request( "/books/json_find_books", options );
ポイントはURLが "/
responseCompleteは次のような感じのメソッドです。
responseComplete: function( transport, json ) { var jsonString = transport.responseText; var object = eval(jsonString); //・・・ }
transportオブジェクトはいわゆるXMLHttpRequestオブジェクトです。jsonはレスポンスのHeadersに'X-JSON'として渡された文字列をevalしたものです。ここではresponseTextをevalしてオブジェクトをゲットしているので、関係ありません。本当はstatusとかを判断したりする処理が必要な気もするけど、省略してます。
また、Functionのbindメソッドに引数を追加すると、呼び出されるときの引数の前に、追加された引数のオブジェクトが渡されます。下の例ではcallbackが追加された引数です。
this.responseComplete.bind(this, callback)
responseComplete: function( callback, transport, json ) {
考えてみたらRPCと呼ぶには面倒くさいやり方ですね。メソッドを呼び出していることは間違いなけど、透過的じゃないというか。でも魔法みたいに見える部分が少なくて良いかも。だんだん面倒くさくなるんだろうけど。