Rails　パーシャル(部分テンプレート)へローカル変数を渡したいとき

# はじめに
パーシャル内でインスタンス変数を使用していたら、ローカル変数を使用すべきと、ご指摘をいただきました。
本記事では、その際に調べたことについて、目次に沿ってご紹介いたします。

表題の内容のみをお求めの方は、**目次の3.から**お読みください。
パーシャルって何それ？おいしいの？って方は、最初からお読みいただければと思います。

環境 `Rails 5.2.1`

1. パーシャルとは
2. パーシャルの基本的な使い方
2. パーシャルに変数を渡したいとき
    1. localsオプション
    2. collectionオプション
3. なぜパーシャル内でインスタンス変数を使用してはいけないか？
4. おわりに

# 1. パーシャルの目的
そもそもパーシャルってなんだ？

>3.2 パーシャル
部分テンプレートまたはパーシャルは、出力を扱いやすく分割するための仕組みです。パーシャルを使用することで、ビュー内のコードをいくつものファイルに分割して書き出し、他のテンプレートでも使いまわすことができます。

参照　[RAILS GUIDES](https://railsguides.jp/action_view_overview.html#%E3%83%91%E3%83%BC%E3%82%B7%E3%83%A3%E3%83%AB)

パーシャルを切る目的
・使用するView内が構造化されて、可読性と汎用性の向上につなげる

#2. パーシャルの基本的な使い方

```Erb:foobar.html.erb
<%= 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`の中身を他のファイルで使用したい時、
コピペで済むとは言え、この長い内容を再度貼り付けなければなりません。

```Erb:foobar_no_partial.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を使用して利用したいパーシャル内で呼び出します。


```Erb:other_file.html.erb

<%= render 'shared/light_section' %>

<section class="mainContent clearfix">
(省略)
</section>
```
以上のことから、パーシャルを活用した方が汎用性も可読性も上がりそうですね。

# 3. パーシャルにローカル変数を渡したいとき
本記事のメインです。まずは結論から。
### 1. localsオプション
```Erb:foobar.html.erb
中略
<%= render partial: 'product_body', locals: { product: @product } %>
　　　　　　　　　　　　パーシャル名　　ローカル変数名： インスタンス変数名
省略形
<%= render 'product_body', product: @product %>
```


```Erb:_product_body.html.erb
 <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`)ということにします。

```Erb:foobar.html.erb
<%= render partial: 'related_products', collection: @related_products %>
　　　　　　　　　　　　  パーシャル名　　　　          インスタンス変数名

応用
<%= render partial: 'related_products', collection: @related_products, as: :related_product %>
asオプションで、related_productというローカル変数名で使用可能になります。
```


```Erb:_related_products.html.erb
collectionオプション　使用前
<% @related_products.each do |product| %>
  <%= product.name %>
  <%= product.price %>
<% end %>

↓

collectionオプション　使用後
<%= product.name %>
<%= product.price %>
```
**collectionオプションを使用するメリット**
・eachを使用せずに、collectionで指定した要素を１つずつ出力してくれる
  (指定した要素の数だけ部分テンプレートが繰り返される)
・コードが短くなる
・インスタンス変数をパーシャル内で使用しなくなった

## 4. なぜパーシャル内でインスタンス変数を使用してはいけないか？
部分テンプレートの再利用性が低くなる（依存度が高くなってしまう）ため。

## 5. おわりに
ご一読ありがとうございました。
不適切な表現やご指摘ございましたら、ただちに修正いたしますので、ご一報いただけると幸いです。