スコープを活用して部分テンプレートを扱う
はじめに
スコープを上手に活用して部分テンプレートを扱うことで可読性をあげるとともに無駄のないコードを書いていこう。
背景
スコープのことなど深く考えずに部分テンプレートを量産して、インスタンス変数をlocalsで渡さずに使ってたら友人のスーパーエンジニアさいぬ君(kattyan310)に指摘されたのでそのことについてまとめておく。
実例〜解決策
localsを使わず、コントローラーで定義したインスタンス変数を使うと異なるコントローラーの時に毎回同じインスタンス変数を定義しなくてはいけないことになる。
- localsを使わない場合
# コントローラー1 class UsersController < ApplicationController def index @names = User.all end end # ビューファイル1 <%= render partial: "index" %> # コントローラー2 class GroupsController < ApplicationController def index @names = Group.all end end # ビューファイル2 <%= render partial: "index" %> # 部分テンプレート <% @names.each do |name| %> <%= name %> <% end %>
また、コントローラーから部分テンプレートまではツリー構造(コントローラー→ビュー→部分テンプレート)になっているので、インスタンス変数のスコープ範囲が広すぎる。 そのため、規模が大きくなると、部分テンプレートからコントローラーで定義しているインスタンス変数を探すのが大変である。
- localsを使う場合
# コントローラー1 class UsersController < ApplicationController def index @user_names = User.all end end # ビューファイル1 <%= render partial: "index", locals: { names: @user_names } %> # コントローラー2 class GroupsController < ApplicationController def index @group_names = Group.all end end # ビューファイル2 <%= render partial: "index", locals: { names: @group_names } %> # 部分テンプレート <% names.each do |name| %> <%= name %> <% end %>
localsで定義してあげることで、部分テンプレートが関数として捉える事ができ、どのような値を与える事でどのように値を加工して、出力してくれるのかがわかる。
また、部分テンプレートがコントローラーとは依存せず、インスタンス変数のスコープ範囲がコントローラーとビューファイルに収まり、可読性も上がる。
最後に
部分テンプレートには、変数をlocalsで渡すようにする。
理由は、
- 可読性が上がる。
- 異なるコントローラー毎に同じインスタンス変数を定義しなくて良い。