Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

はじめに

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

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

環境 Rails 5.2.1

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

1. パーシャルの目的

そもそもパーシャルってなんだ?

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

参照 RAILS GUIDES

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

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

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

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

other_file.html.erb
<%= render 'shared/light_section' %>

<section class="mainContent clearfix">
(省略)
</section>

以上のことから、パーシャルを活用した方が汎用性も可読性も上がりそうですね。

3. パーシャルにローカル変数を渡したいとき

本記事のメインです。まずは結論から。

1. localsオプション

foobar.html.erb
中略
<%= render partial: 'product_body', locals: { product: @product } %>
            パーシャル名  ローカル変数名: インスタンス変数名
省略形
<%= render 'product_body', product: @product %>
_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)ということにします。

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

応用
<%= render partial: 'related_products', collection: @related_products, as: :related_product %>
asオプションで、related_productというローカル変数名で使用可能になります。
_related_products.html.erb
collectionオプション 使用前
<% @related_products.each do |product| %>
  <%= product.name %>
  <%= product.price %>
<% end %>

↓

collectionオプション 使用後
<%= product.name %>
<%= product.price %>

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

4. なぜパーシャル内でインスタンス変数を使用してはいけないか?

部分テンプレートの再利用性が低くなる(依存度が高くなってしまう)ため。

5. おわりに

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

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away