Ktouth Brand. on Web

け〜くんこと K.Ktouth のだらだらした日常と突発的に作るプログラムや読み物とかの雑多サイト



[2011年01月23日]

render_xxx の落とし穴

2011年01月24日 08:46更新 筆者:K.Ktouth

朝からページビューのキャッシング機構を作ろうとして、この落とし穴に同時にハマったせいでやたらとデバッギングに時間がかかった orz

Innate には render ヘルパーモジュールというものがあり、各コントローラにこのヘルパーを登録するだけで render_partial 等の分割レンダリング機能が利用可能になります。
また、コントローラのインスタンス変数もきちんと伝播するので、やりようによっては大分楽にビューの記述が可能になるのですが……

# コントローラのメソッド
def foobar
 @count = 10
end

# 対応するビューファイル: view.html
<ul class="count<%= @count %>">
 <li><p>ここは第<%= @count %>階層です</p>
  <% if @count > 0 %>
  <%  @count = @count - 1 %>
  <%= render_view(:foobar) %>
  <% end %>
 </li>
</ul>

非効率的な例ですが、簡単な階層構造を生成するアクションです。階層ごとにビューファイルを用いてリストを多段化しています。
……が。これを実行すると無限ループに陥りますげー

(以下、対処方法)

原因は赤で表記した部分。
コントローラで設定したインスタンス変数はビューの中で使用可能ですから、つい簡単な操作を行いたくなりますが……インスタンス変数に代入する行為だけはうまく継承されません
render ヘルパーによって導入される render_xxxx というメソッドは、内部で新しいアクションを生成し、呼び出し元コントローラのインスタンス変数を反映させます。が、呼び出し元は最初のコントローラのアクションに固定されているので、ビューファイルの中で行ったインスタンス変数への代入は呼び出し元コントローラには当然ながら反映されません。参照や破壊的操作およびビューファイル内部で完結するインスタンス変数の代入は正しく動作します。(ビューファイル内部で完結するならインスタンス変数である必要はないでしょうが)

常にダメならすぐに気づくんでしょうが、render ヘルパーではなく、通常の方法でコントローラから呼び出されたビューファイルではインスタンス変数の代入がうまく動作するため、余計に気づきにくかったります。

結論。
ビューファイル内でインスタンス変数に代入するなぐっど

本日のリンク元
アンテナ
その他のリンク元
検索