Railsで直接Controllerを叩いてrenderの結果を得る方法

Controller中で他のcontrollerと actionを叩いてその結果を得ることが出来たら便利だと思いませんか?例えば HogeControllerと MogeCotrollerがあって、Hoge#fooが呼ばれたときに Moge#barが呼ばれたときと同じ結果を出したいとか。 これは Moge.new.barとかやってもうまくいきませんが、次のようにすると出来ます。

MyApp::Application.routes.call('REQUEST_METHOD' => 'GET', 
        'rack.input' => '', 'SCRIPT_NAME' => '', 'PATH_INFO' => path)[2].body

これでpathで示される場所に存在するcontrollerとアクションが起動し、その結果が文字列で帰ってきます。多分Rails3.1以上はこれでいいはず。ただし、これだとsessionやらcookieが渡されないので、それをも利用したい場合は次のように書けばよいでしょう。

options = request.env.dup
options = options.select {|k|
      k == "HTTP_COOKIE" or k == "rack.session" 
}
options = options.dup.merge('REQUEST_METHOD' => 'GET', 'rack.input' => '', 'SCRIPT_NAME' => '', 'PATH_INFO' => path)
MyApp::Application.routes.call(options)[2].body

これでrotes.rbを書き換えずに、特定のpathと controller#actionが紐づいているように見えます。

「そんなやり方は邪道」とか「これはMVCモデルじゃねぇよ」とかいう声が聞こえてきそうですが、現実的にはMVCと綺麗に分離できることなんて稀だし、現実的には色々な要求があちこちからあるのでMVCが邪魔になることってあるんですよね。知ってて損は無いと思いますよ。

Posted by issei

カテゴリ: 雑記