【Rails】部分テンプレートの使い方を徹底解説!

Rails

部分テンプレートとは

複数のビューファイルの中で使われている部分を一つのビューファイルとして管理する時に使います。

application.html.erbにはヘッダーやフッターなど全てのビューファイルで共通する部分を記述しました。
この他にもアプリを作成しているとサイドバーなど複数のページで共通して表示させたい部分が結構あります。
そんな時に、複数のビューファイルの共通部分として作成するのが部分テンプレートです。

部分テンプレートを作成しよう

部分テンプレートとしてビューファイルを作成する時は「_sidemenu.html.erb」のようにファイル名の前に「 _ 」(アンダースコア)をつける必要があります。

このようなファイル名で作成すると部分テンプレートとして使うことができます。

部分テンプレートを呼び出してみよう

それでは今作成した部分テンプレートを呼び出してみましょう。
コントローラーやビューファイルの中でビューファイルを呼び出すにはrenderメソッドを使用します。

renderメソッド

指定したテンプレートを呼び出す時に使うメソッドです。
下記のように記述します。

ruby
1
2
render 'ファイル名'      # 指定したテンプレートファイルを呼び出す
render :アクション名    # 指定したアクションのテンプレートファイルを呼び出す

renderメソッドは色々な形でビューを呼び出すことができます。
そのため「部分テンプレートを呼び出しているよ」ということを明示的にする時はオプションを使って下記のように記述することもできます。

ruby
1
render partial: 'ファイル名'

renderメソッドを記述したビューファイルと違うフォルダ内の部分テンプレートを呼び出すときは hoges/hogeのようにどのフォルダの部分テンプレートを使用しているかを記述する必要があります。

ruby
1
render partial: 'hoges/hoge'

下の例だと_right_content.html.erbはこのコードを記述しているindex.html.erbと同じフォルダにあるのでそのままファイル名を記述すれば呼び出すことができます。

_menu_html.erbはlayoutsフォルダ内にあるので、呼び出す際は「 layouts/menu 」と記述する必要があります。

部分テンプレート呼び出し

partialオプション

partialオプションは部分テンプレートを呼び出す時に使います。
「呼び出しているのは部分テンプレートだよ」と強調したいだけなので、つけなくても構いません。

ですがlocalsオプションを使用した時はつけないとエラーが出ます。

localsオプション

localsオプションを使うと部分テンプレート内で使う変数の定義をすることができます。
例えば部分テンプレート内で変数を使いたい場合、どこかで変数を定義する必要がありますね。
そんな時にはlocalsオプションを使って変数を定義します。

erb
1
2
3
4
5
6
<%= render partial: 'ファイル名', locals: { '部分テンプレート内で使う変数': '変数に入れる値' } %>
<!--例 テンプレート内の「hoge」という変数に「こんにちは」が代入される -->
<%= render partial: 'hoge', locals: { hoge: 'こんにちは' } %>

<!-- 例 テンプレート内の「hoge」という変数に呼び出し元で定義した変数「hoge」が代入される-->
<%= render partial: 'hoge', locals: { hoge: hoge } %>

なおlocalsオプションは下記のように省略して書くこともできます。

erb
1
<%= render partial: 'hoge', hoge: hoge %>

この時はpartialも省略して書くことができます。

erb
1
2
3
4
<%= render 'hoge', hoge: hoge %>

<!-- localsオプションを記述しているとエラー -->
<%= render 'hoge', locals: { hoge: hoge } => エラーが発生 %>

変数を複数定義してみよう

localsオプションでは部分テンプレート内で使用する変数を複数定義することができます。
例をみてみましょう。

erb
1
<%= render partial: 'hoge', locals: { name: "山田", adress: "東京都渋谷区", age: 20 } %>

上の例だと部分テンプレート内で使用するnameadressageという3つの変数を定義しています。
実際に部分テンプレート内で使用してみます。

3つの変数

このように記述すると下のように表示されます。

私の名前は山田です。

このように部分テンプレートで使用する変数は複数定義することもできます。

記述例を見てみよう

それでは実際部分テンプレートをどのように使うのか確認してみましょう。
今回はnewアクションとeditアクションで使うビューを例にしてみます。

コントローラー

ruby
1
2
3
4
5
6
7
def new
  @article = Article.new
end

def edit
  @article = Article.find(params[:id])
end

new.html.erb

erb
1
2
3
4
5
6
7
8
9
<%= form_for @article do |f| %>
  <%= f.label :name %>
  <%= f.text_field :name %>
  <%= f.label :title %>
  <%= f.text_field :title %>
  <%= f.label :body %>
  <%= f.text_area :body %>
  <%= f.submit %>
<% end %>

edit.html.erb

erb
1
2
3
4
5
6
7
8
9
<%= form_for @article do |f| %>
  <%= f.label :name %>
  <%= f.text_field :name %>
  <%= f.label :title %>
  <%= f.text_field :title %>
  <%= f.label :body %>
  <%= f.text_area :body %>
  <%= f.submit %>
<% end %>

投稿フォームと編集フォームはform_forというヘルパーメソッドを使っているため、全く同じコードで書くことができます。
ですのでここは部分テンプレートとして置き換えられそうですね。

共通する部分を「_form.html.erb」という名前のファイルを作成し記述します。
今回はローカル変数として変数を定義するので「@article」から「article」に変えておきます。

※インスタンス変数だと使われる範囲が部分テンプレートの中だけに限定することができないため

_form.html.erb

erb
1
2
3
4
5
6
7
8
9
<%= form_for article do |f| %>
  <%= f.label :name %>
  <%= f.text_field :name %>
  <%= f.label :title %>
  <%= f.text_field :title %>
  <%= f.label :body %>
  <%= f.text_area :body %>
  <%= f.submit %>
<% end %>

そしてnew.html.erbedit.html.erbを下記のように編集します。

erb
1
<%= render partial: 'form', locals: { article: @article } %>

「partial:」の部分は部分テンプレート名を記述するのでした。
部分テンプレート名は「_form」とアンダーバーが付いていますが、呼び出す際は「 _ 」は付けません。

また今回は部分テンプレート内で「article」という変数を使っているので「 locals: { article: @article }」と指定します。

左の「article」の部分は部分テンプレート内で使うときの変数名を記述します。
今回作成した部分テンプレート「_form.html.erb」の中では「article」という変数を使っているので「article」と指定しています。

右の「@article」の部分はコントローラーやビューで定義した変数名を記述します。
今回はコントローラーのnewアクションとeditアクションで定義した「@article」を指定しています。

new.html

上のコードが下の1行のコードになりました。

renderメソッドを使った時

もちろんnew.html.erbだけでなくedit.html.erbも1行で書くことができます。

edit.html

このように共通している全てのファイルで部分テンプレートを呼び出す記述に置き換えることができます。

比較

左が部分テンプレート導入前、右が部分テンプレート導入後です。
コードがかなりスッキリしましたね!

他のオプションを確認してみよう

renderメソッドには他にもオプションが用意されています。
例えば下記のようなコードがあったとします。

erb
1
2
3
4
5
<% @hoges.each do |hoge| %>
  <%= hoge.name %>
  <%= hoge.title %> 
  <%= hoge.body %>
<% end %>

このコードが何箇所でも使われているので下記のような部分テンプレートを作成したとします。

_hoge.html.erb

この部分テンプレートを使用するので下記のようにビューファイルを編集します。

erb
1
2
3
<% @hoges.each do |hoge| %>
  <%= render partial: 'hoge', hoge: hoge %>
<% end %>

上のコードは@hogesの要素の分だけ部分テンプレートが繰り返し呼び出されて表示されます。

この3行のコードをcollectionオプションを使うと下記のように1行で記述することができます。

erb
1
<%= render partial: 'hoge', collection: @hoges %>

collectionオプション

collectionオプションを使用するとcollectionオプションに指定した変数の要素の分だけ部分テンプレートが繰り返し表示されます。

erb
1
<%= render partial: 'hoge', collection: 繰り返し表示する要素が入っているインスタンス %>

先ほどの例だと@hogesにはhogesテーブルから繰り返して表示させたいレコードを取得して代入してあります。

そうすると自動で一つ一つの要素が取り出され部分テンプレートに渡されて繰り返し表示されるという流れになります。

またcollectionオプションを使用する時は「partial:」を記述しないとエラーになるので気をつけましょう。

部分テンプレート内で使う変数を変更する場合

collectionオプションを使用した場合、部分テンプレート内で使用する変数はオプションで指定した変数が「@hoges」であったらその単数形の「hoge」になります。
もし別の名前として変数を使いたい場合は下記のように記述します。

erb
1
<%= render partial: 'hoge', collection: @hoges, as: "fuga" %>

この時、@hogesに入っている要素が一つずつ取り出され、部分テンプレート内の変数「fuga」に代入されます。

asオプション

このように記述すると@hogesの要素が一つずつfugaという変数に代入され、部分テンプレート内で使用することができます。

パフォーマンスに注意しよう

繰り返し部分テンプレートを使う場合、each文の中に記述するかcollectionオプションを使うか2つの方法があるということがわかりました。

どちらを使っても問題なく表示されるのですが、決定的な違いがあります。
それはパフォーマンスの問題です。

パフォーマンス

ITの世界のパフォーマンスはコンピュータの処理や実行速度のことを言います。
「パフォーマンスが悪くなる」というのは「実行速度が遅くなる」ということを意味します。

collectionオプションを使用して記述すると部分テンプレートが呼び出されるのは1回のみなので、eachで表示するよりもパフォーマンスが良くなります。

では実際どれくらいの違いがあるのでしょうか?
2つの例で確認してみましょう。

1000回の呼び出し

上の例では1000回部分テンプレートを呼び出しました。
確認すると呼び出すのに合計で2945.8msかかっているのがわかります。

下の例はcollectionオプションを使った時の結果です。

collectionオプション

collectionオプションを使うと1回しか読み込まれないので136.7msしかかかっていません。
1,000回呼び出すことはまずないと思いますが、これだけの差になってしまいます。
ですので部分テンプレートを繰り返し呼び出す時は出来るだけcollectionオプションを使う記述にしましょう。

省略した書き方

下のコードが次の条件を全て満たしている時、このコードを省略して書くことができます。

erb
1
<%= render partial: 'hoge', collection: @hoges %>
  • 呼び出す部分テンプレートがviewsフォルダ内にあるhogesフォルダに存在する
  • 部分テンプレート名が_hoge.html.erbである
  • 部分テンプレート内で使う変数が「hoge」である

上の条件を全て満たしていると下記のように省略できます。

erb
1
<%= render @hoges %>

このコードは下のコードと全く同じ結果になります。

erb
1
2
3
4
5
6
7
<!--下のコードと全く同じ -->
<%= render partial: 'hoge', collection: @hoges %>

<!--もしくは下のコードと全く同じ -->
<% @hoges.each do |hoge| %>
  <%= render partial: 'hoge', hoge: hoge %>
<% end %>

この場合、viewsフォルダのhogesフォルダ内にある部分テンプレート「_hoge.html.erb」を自動で選択してくれます。
かなり簡潔に書くことができますね!

部分テンプレートを使うメリット

部分テンプレートを使った時と使わない時ではビューの表示は全く変わりません。
それではなぜ部分テンプレートを使うのでしょうか?
部分テンプレートを使うメリットをいくつかあげてみます。

  • 複数箇所で使われているコードに対し、同じ記述を書かなくてすむ
  • main_content, footerのように命名規則でどの部分の記述をしてるかコードを見なくてもわかる
  • 一つのファイルにコードを書き過ぎることがなくなり可読性が上がる

それではメリットを一つずつ確認していきましょう。

同じ記述を書かなくてすむ

例えばフォームに入力してもらう内容を変えたい場合、ファイルを編集する必要がありますね。

部分テンプレートを使う前だとnew.html.erbedit.html.erbの2つのファイルを編集する必要がありました。

ですが部分テンプレートとして切り分けると部分テンプレートだけ編集すれば良いので作業効率が上がったり、修正ミスが少なくなるなどというメリットがあります。

コードをみなくても内容がわかる

部分テンプレートの名前を「header」や「menu」などの名前にしておくと、そのコードをみなくても「ああ、ここはヘッダーの部分なんだな」などコードの内容がとてもわかりやすくなります。

可読性が上がる

また一つのビューファイル自体が非常にコンパクトになります。
下の例を見てみましょう。

トップページ

このようなビューファイルがあった時、上のメニューと右カラムは複数のビューファイルで使われているとします。
ですので部分テンプレートを作成し、ビューを切り分けてみましょう。

切り分け後

するとこのようにビューファイルがスッキリしましたね!
長いコードになってしまうとコードが非常に読みにくくなります。
できれば一つのビューファイルは100行以内に収まるようにするのが良いでしょう。

このように部分テンプレートを使うとビューの管理がだいぶ楽になります。
重複する箇所を見つけたら部分テンプレートしてまとめておきましょう。

まとめ

部分テンプレートは複数のビューファイル内で使われている部分を一つのファイルにまとめて使いまわすことができる大変便利なものです。