はじめに
パーシャル内でインスタンス変数を使用していたら、ローカル変数を使用すべきと、ご指摘をいただきました。
本記事では、その際に調べたことについて、目次に沿ってご紹介いたします。
表題の内容のみをお求めの方は、目次の3.からお読みください。
パーシャルって何それ?おいしいの?って方は、最初からお読みいただければと思います。
環境 Rails 5.2.1
- パーシャルとは
- パーシャルの基本的な使い方
- パーシャルに変数を渡したいとき
- localsオプション
- collectionオプション
- なぜパーシャル内でインスタンス変数を使用してはいけないか?
- おわりに
1. パーシャルの目的
そもそもパーシャルってなんだ?
3.2 パーシャル
部分テンプレートまたはパーシャルは、出力を扱いやすく分割するための仕組みです。パーシャルを使用することで、ビュー内のコードをいくつものファイルに分割して書き出し、他のテンプレートでも使いまわすことができます。
参照 RAILS GUIDES
パーシャルを切る目的
・使用するView内が構造化されて、可読性と汎用性の向上につなげる
#2. パーシャルの基本的な使い方
<%= render 'shared/light_section' %>
<section class="mainContent clearfix">
<div class="container">
<div class="media">
<%= render 'thumbnail' %>
<%= render 'product_body' %>
</div>
</div>
</section>
上の例の場合、
<%= render 'shared/light_section' %>
はshared
というディレクトリの中にある、_light_section.html.erb
というパーシャルを、render先として指定しています。
*例
- shared (ディレクトリ)
- _light_section.html.erb*
<%= render 'thumbnail' %>
はfoobar.html.erb
が格納されている同一ディレクトリ(hogehogeディレクトリ
)から参照されています。
*例
- hogehoge (ディレクトリ)
- _thumbnail.html.erb
- _product_body.html.erb
- foobar.html.erb*
なお、パーシャル作成時はその他のViewファイルと区別をするために、
_hogehoge.html.erb
のようにファイル名に先頭にアンダーバーをつけます。
パーシャルをつけないとどうなるか?
こちらは、上の例の<%= render 'product_body' %>
を使用していないVer.になります。
<%= render 'thumbnail' %>
と<%= render 'shared/light_section' %>
のパーシャルは、
使用しているにも関わらず、かなり見にくくなってしまいます。
更に、_product_body.html.erb
の中身を他のファイルで使用したい時、
コピペで済むとは言え、この長い内容を再度貼り付けなければなりません。
<%= render 'shared/light_section' %>
<section class="mainContent clearfix">
<div class="container">
<div class="media">
<%= render 'thumbnail' %>
<div class="media-body">
<ul class="list-inline">
<li>
<%= link_to hoge_path do %>
<i class="fa fa-reply" aria-hidden="true"></i>一覧ページへ戻る
<% end %>
</li>
</ul>
<h2><%= @product.name %></h2>
<h3><%= @product.display_price %></h3>
<p><%= @product.description %></p>
(省略)
コードはまだまだ続いてると仮定
</div>
</div>
</section>
他のViewでshared/light_section
を引き続き使用したいと仮定します。
単純にrenderを使用して利用したいパーシャル内で呼び出します。
<%= render 'shared/light_section' %>
<section class="mainContent clearfix">
(省略)
</section>
以上のことから、パーシャルを活用した方が汎用性も可読性も上がりそうですね。
3. パーシャルにローカル変数を渡したいとき
本記事のメインです。まずは結論から。
1. localsオプション
中略
<%= render partial: 'product_body', locals: { product: @product } %>
パーシャル名 ローカル変数名: インスタンス変数名
省略形
<%= render 'product_body', product: @product %>
<div class="media-body">
<ul class="list-inline">
<li>
<%= link_to hoge_path do %>
<i class="fa fa-reply" aria-hidden="true"></i>一覧ページへ戻る
<% end %>
</li>
</ul>
↓ ココに注目
<h2><%= product.name %></h2>
<h3><%= product.display_price %></h3>
<p><%= product.description %></p>
(以下、省略)
</div>
localsオプションを使用したことによって、@product
というインスタンス変数をproduct
というローカル変数にした状態で、_product_body.html.erb
に渡すことができました。
2. collectionオプション
同様にfoobar.html.erb
を使用した例ですが、パーシャルは(_related_products.html.erb
)ということにします。
<%= render partial: 'related_products', collection: @related_products %>
パーシャル名 インスタンス変数名
応用
<%= render partial: 'related_products', collection: @related_products, as: :related_product %>
asオプションで、related_productというローカル変数名で使用可能になります。
collectionオプション 使用前
<% @related_products.each do |product| %>
<%= product.name %>
<%= product.price %>
<% end %>
↓
collectionオプション 使用後
<%= product.name %>
<%= product.price %>
collectionオプションを使用するメリット
・eachを使用せずに、collectionで指定した要素を1つずつ出力してくれる
(指定した要素の数だけ部分テンプレートが繰り返される)
・コードが短くなる
・インスタンス変数をパーシャル内で使用しなくなった
4. なぜパーシャル内でインスタンス変数を使用してはいけないか?
部分テンプレートの再利用性が低くなる(依存度が高くなってしまう)ため。
5. おわりに
ご一読ありがとうございました。
不適切な表現やご指摘ございましたら、ただちに修正いたしますので、ご一報いただけると幸いです。