RubyOnRailsとjQueryで簡単クロスドメインajax
Railsのサーバーと非RailsのWebサービス(どちらも自前で管理)のクロスドメインajaxをやってみたら、思いのほか簡単だったので、記事にしてみます。
なお、クロスドメインに関するセキュリティ的な話題はいろいろあると思いますので、そのあたりは自分で調べてみてください。
サンプルコードに関して
こちらにサンプルコードを載せたので、もしよければ参考にしてください。 https://github.com/sakairyota/jsonp_example
本文中のコードは下記のファイルに含まれています
app/controllers/entries_controller.rb config/routes.rb public/test_jsonp.html
public/test_jsonp.html はRailsのサーバーから開くと同一ドメインの通信、ファイルシステムから開くとクロスドメインとなり、気軽にそれぞれを試すことができるようになっています。
クロスドメイン制約
JavaScriptにはクロスドメインの制約があります。たとえは、example.comにあるファイルを、はてな(hatena.ne.jp)のページに配置したJavaScriptから通信して取得することはできないようになっています。
JSONP
しかし、JSONPを使うとクロスドメインの壁を超えることができます。JSONPではsrcにファイルのURLを含めたscriptタグを生成して、JavaScriptを実行させます。たとえば、hatena.ne.jpで、srcにexample.com/hogeのファイルを指定したscriptタグを生成すると、生成した時点で、example.com/hogeのJavaScriptが実行されます。
JavaScriptでの通信はドメインを超えることができないのに対し、Scriptタグで外部のドメインのスクリプトを読み込むことができることを利用しています。
RailsでJSON
Railsでは、標準ではviewsに配置されているhtmlのテンプレートを元にhtmlを返しますが、respond_toを使うと、JSONやxmlを返すことができるようになります。
class EntriesController < ApplicationController def show @entry = {id: params[:id], title: "entry#{params[:id]}", content: "This is content ##{params[:id]}"} respond_to do |format| format.json { render json: @entry} end end end
説明のため @entry にハッシュを代入していますが、実際には Entry.find params[:id] などが入ります。
resources :entries, only: :show
ルーティングを上のように設定すると、http://localhost:3000/entries/1.json というように.jsonを付けてJSONを取得することができます。
{ "id": "1", "title": "entry1", "content": "This is content #1" }
RailsでJSONP
そこで、コードを次のように変更します。
class EntriesController < ApplicationController def show @entry = {id: params[:id], title: "entry#{params[:id]}", content: "This is content ##{params[:id]}"} respond_to do |format| format.json { render json: @entry, callback: params[:callback]} end end end
差分
- format.json { render json: @entry} + format.json { render json: @entry, callback: params[:callback]}
すると、JSONPが使えるようになります。http://localhost:3000/entries/1.json?callback=hoge でアクセスすると次のようなJavaScriptが返ってきます。
hoge( { "id": "1", "title": "entry1", "content": "This is content #1" } )
参考にした記事(2年も前ですが): http://labs.s-koichi.info/blog/archives/2008/03/04/2231-60.php
jQueryからajax(JSONP)
jQueryでは $.ajax を使って、簡単にAjaxを実装することができます。
例えば、次のように $.ajax に url と success のコールバックを指定すると、先ほどのjsonを読み込んで、htmlに書き出すことができます。
$.ajax({ url: 'http://localhost:3000/entries/1.json', success: function(json){ $('#entry .entry_id').text(json['id']); $('#entry .title').text(json['title']); $('#entry .content').text(json['content']); } });
jQueryからajax(JSON)
そこで、$.ajax で dataType のパラメータにjsonpを指定します。すると、JSONPでのアクセスとなり、クロスドメインのAjaxが実現できます。
$.ajax({ url: 'http://localhost:3000/entries/1.json', dataType: 'jsonp', success: function(json){ $('#entry_jsonp .entry_id').text(json['id']); $('#entry_jsonp .title').text(json['title']); $('#entry_jsonp .content').text(json['content']); } });
差分
+ dataType: 'jsonp',
ね、簡単でしょう?
最後に
ajaxでデータを取得するところまでは簡単にできました。
これを実践した時には、この後の受け取ったデータを処理するところに手間取ったということは、「簡単」をうたっているのに対して水をさすので、 この記事では書かないでおきます。