部分テンプレート render @posts どういう意味?


はじめに

Ruby on Railsではコードの可読性や管理性を重視し、複数のビューファイルで共通するコードを一つのビューファイルにまとめ、部分テンプレートとして使用することが好まれています。
そこで、Railsの教材を元に、部分テンプレートの作成をしていたところ

index.html.erb
<%= render @posts %>

という謎のコードが出てきました。
呼び出された部分テンプレートは _post.html.erb でサーバーを起動すると、Postテーブルに登録された投稿の数だけ投稿のタイトルと内容が繰り返し表示されています。
render + インスタンス変数に何が隠されているのか調べてみました。

序論

今、投稿一覧ページ (index.html.erb) にはPostテーブルの要素の数だけ投稿のタイトルと内容が繰り返し処理により表示されている状態です。
すなわち、本来 index.html.erb ファイルは

index.html.erb
<% @posts.each do |post| %>
  <%= post.title %>
  <%= post.content %>
<% end %>

こうあるべきです。

それがなぜ

index.html.erb
<%= render @posts %>

このように記述されたのか順を追って解説します。

patialオプション

まず、

index.html.erb
<% @posts.each do |post| %>
  <%= post.title %>
  <%= post.content %>
<% end %>

このコードの投稿のタイトルと内容を表示する部分からテンプレートを作成します。部分テンプレートのファイル名は必ずアンダーバーから始まるので_post.html.erb と設定します。

_post.html.erb
<%= post.title %>
<%= post.content %>

このようになります。

この部分テンプレートを呼び出すために index.html.erb にrenderメソッドを用います。

index.html.erb
<% @posts.each do |post| %>
 <%= render partial: 'post', locals: {post : post} %>
<% end %>

部分テンプレート名は_postですが、呼び出す際はアンダーバー無しのpostで呼び出します。

renderメソッド内のpartialオプションは、「部分テンプレートを呼び出すよ!」と明示させるためのものなので省略可能です。

ただし、今回のようにlocalsを記述している場合はpartialを記述しないとエラーが出てしまいます。

localsオプション

部分テンプレートを呼び出すコードに
<%= render partial: 'ファイル名', locals: {部分テンプレート内の変数 : 変数に入れたい値} %>
localsとあります。

localsオプションを用いると、部分テンプレート内で使う変数の定義をすることができます。

今回の例では”部分テンプレート内の「post」という変数”に”呼び出し元で定義した変数「post」”が代入されています。

collectionオプション

さて、部分テンプレートによって

index.html.erb
<% @posts.each do |post| %>
 <%= render partial: 'post', locals: {post : post} %>
<% end %>

このようにコード量を減らすことができました。

上記のコードは@postsの要素の分だけ部分テンプレートが繰り返し呼び出されています。そこでcollectionオプションを用いてコードをさらにスッキリさせたいと思います。

index.html.erb
<%= render partial: 'post', collection: @posts %>

collectionオプションを用いると、なんと3行あったコードを1行で書くことができます。

collectionオプションとは指定した変数の要素の分だけ、部分テンプレートを繰り返し表示できるオプションです。
すなわち元のコードの”each文”と”localsオプション”の機能を担っています。

「え?localsで指定した変数は?」と思いますよね。

collectionオプションでは指定した変数(@posts)の単数形(post)が自動的に、変数に入れたい値として指定されます。

もしcollectionオプションを用いて変数も指定したい場合は
<%= render partial: 'post', collection: @posts, as: "指定したい変数名" %>
で指定できます。

まだ省略できる!?

index.html.erb
<%= render partial: 'post', collection: @posts %>

このように最初に比べかなりスッキリしたコードですが、ある条件を満たせばさらに省略できます。

  1. 呼び出す部分テンプレートが、views/posts内に存在する
  2. 部分テンプレート名が_post.html.erbである
  3. 部分テンプレート内の変数がpostである

上記の条件を満たす場合、下記のコード量まで省略可能です。

index.html.erb
<%= render @posts %>

なんと!!見覚えのあるコードですね!!!さっきまで全く理解できなかったコードです。

render + インスタンス変数にここまでの情報が詰まっているとは、、、

結論

render + インスタンス変数で構成された

index.html.erb
<%= render @posts %>

このコードには、views/posts内の部分テンプレート

_post.html.erb
<%= post.title %>
<%= post.content %>

@postsの要素の分だけ繰り返し呼び出す処理が隠されていました。

renderメソッドのpartial,locals,collectionオプション、さらには省略の条件まで理解してようやく納得できます。
簡単に書かれたコードほど初心者泣かせですよね、、、

参考文献