Edge Rails における Controller#respond_to
Rails 1.1.2における Controller#respond_to の機能は くまくまーの人がまとめているのを参考にすればよいのですが,Edge RailsではRubyKaigi2006のDHHの講演でも触れられていたようにさらに機能が追加されています.
ところで Controller#respond_to の機能をおさらいすると,「同じ処理を入力/出力で異なる形式のデータを介して行う」ためのメソッドで,1つのアクションの中で簡潔にこの出力の切り替えを行うことができるメソッドです.
というわけで全体的にくまくまの人の記事をパクり^h^h^hリスペクトしつつ,主に追加部分について書いてみます.
概要
- params[:format] を見る
- でなければHTTP1.1 リクエストヘッダ中の Accept フィールドを見る
- Content-type に応じてリクエストのデータ形式を自動変換してくれる
- 従って,コントローラは同じロジック(action)で対応できる
- MIMEタイプに応じて実行する描画処理を指定できる
- "*/*" が指定された場合は respond_to の最初の定義を実行する
要するに params[:format] を見る部分だけが増えてます.(あとは対応するMIMEタイプが増えてるとか後付が簡単になったとか)
書式
Controller
respond_to do |format| format.html format.js format.xml { render :action => "#{action_name}.rxml" } format.yaml { render :text => @obj.to_yaml } end
指定しなければ html ならば { render }, js ならば { render :action => "#{action_name}.rjs" }, xml ならば { render :action => "#{action_name}.rxml" } を指定したのと同等です.(そのほかの形式では今のところ省略できません.)
config/routes.rb
GETで ?format=xml を付けるのもいいんですが,せっかくなので routes.rb で拡張子っぽく書けるようにしましょう.
map.connect ':controller/:action/:id.:format' map.connect ':controller/:action/:id'
例
えっと何でもいいんですが,Perfumeのメンバー情報を見ることにします.何でもいいんですが.ええ.
MemberController
def show @member = Member.find(params[:id]) respond_to do |format| format.html format.js format.xml { render :text => @member.to_xml } format.atom { redirect_to :action => :atom } format.yaml { render :text => @member.to_yaml } end end
show.rhtml
<h1><%= @member.nickname %></h1> <h2><%= @member.birthday %></h2>
show.rjs
page.replace_html 'member_nickname', @member.nickname
実行
すべてブラウザからでも問題ありません(最初の例以外はAcceptヘッダの値を考慮する必要はありません)
http://localhost:3000/member/show/2
<h1>のっち</h1> <h2>1988-09-20</h2>
(この場合はAcceptヘッダが考慮され,その値に結果は左右されます.)
http://localhost:3000/member/show/2.html
<h1>のっち</h1> <h2>1988/09/20</h2>
http://localhost:3000/member/show/2.js
try { Element.update("member_nickname", "\u306e\u3063\u3061"); } catch (e) { alert('RJS error:\n\n' + e.toString()); alert('Element.update(\"member_nickname\", \"\u306e\u3063\u3061\");'); throw e }
http://localhost:3000/member/show/2.xml
<?xml version="1.0" encoding="UTF-8"?> <member> ... <nickname>のっち</nickname> <birthday type="date">1988-09-20</birthday> ... </member>
http://localhost:3000/member/show/2.atom
HTTP/1.x 302 Moved Temporarily .. Location: http://localhost:3000/member/atom
入力変換機能
標準では XML 形式を入力に使用できます.
XML の例
% telnet localhost 3000 POST /member/search HTTP/1.1 Host: localhost Accept: application/xml Content-Type: application/xml <query> <birthday>1988-12-23</birthday> </query>
Controller からは params に
{"action"=>"search", "controller"=>"member", "query"=>{"birthday"=>#<Date: 4895037/2.0,2299161>}}
という要素が追加されたように見えます.すなわち,FORMからPOSTされたデータと同じように扱えます.
YAMLの例
標準では使用できませんが,YAML形式に関しては envirionment.rb などで以下のようにすることで使用できます.
ActionController::Base.param_parsers[Mime::Type::lookup('application/x-yaml')] = :yaml
% telnet localhost 3000 POST /member/search HTTP/1.1 Host: localhost Accept: application/xml Content-Type: application/x-yaml --- :query: :birthday: 1988-12-23
params
{"action"=>"search", "controller"=>"member", "query"=>{"birthday"=>#<Date: 4895037/2.0,2299161>}}
結果
<?xml version="1.0" encoding="UTF-8"?> <member> ... <nickname>かしゆか</nickname> <birthday type="date">1988-12-23</birthday> ... </member>
Mime::Type へ登録
environment.rb で以下のようにして登録できます.
Mime::Type.register "text/x-mobile", :mobile
この辺DHHのRubyKaigiのスライドとは引数の順序が違ったりするのでいろいろと注意です.
参考
- http://wota.jp/ac/?date=20060317
- http://techno.hippy.jp/rorwiki/?RubyKaigi2006
- action_pack の CHANGELOG
- ソース (mime_*.rb とか cgi_methods.rb とか)