はじめに
部分テンプレートは、主に内容が重複する部分をまとめるために使われるものです。
内容をまとめることで、後で修正したくなったときも一部だけで良い上に、記述が少なくなってビュー自体が見やすくなります。
今回は、そんな部分テンプレートを使用した際の、私の失敗談について記録します。
部分テンプレートの使い方
部分テンプレートを呼び出す記述
<%= render 'ファイルの場所', テンプレートに記載する変数:上書きする変数 %>
ビューから呼び出す際の基本の書き方はこんな感じです。
部分テンプレートのファイルの場所を指定して、その部分テンプレートに渡す変数を設定します。
例えばこんな感じです。
<%= render 'books/book', new_book: @new_book, user: @user %>
この場合はbooksフォルダの「_book.html.erb」ファイルを表示したいので、新しいデータを入れるための@new_bookとユーザー情報を表示するための@userを渡す変数を指定しました。
私の失敗談
ここからが学習を始めた初期の頃に、頭を悩ませていた私の失敗談になります。
失敗したポイントとしては、
- 部分テンプレートを適切に分割せずに使おうとした
- 変数を渡す記述の意味が分かっていなかった
- 変数名をややこしくしてしまった
失敗した際の記述
部分テンプレートにデータを渡すためにコントローラに書いた変数の指定です。
(今回の内容と関係ない部分は削除していますが、本来は他にも書いてありました。)
def show
@user = User.find(params[:id])
@books = Book.new
end
これだけでは分かりにくいですが、同じコントローラ内のindexアクションや他のコントローラなどでも「@books = Book.all」のように記述している部分がありました。
それにも関わらず、「@books = Book.new」にしてしまったことで、コントローラとビューがなんだか分かりにくくなってしまっています。
この頃は、分かりやすい名前を付けるという意味をいまいち理解できていませんでした…。
そして、ビューから部分テンプレートを呼び出すための記述がこちら。
<%= render 'books/book', book: @books, 'books.user': @user %>
もともと書いていた部分テンプレート内では
<%= book.user.name %>のようになっていて「book.user」が「@user」になれば
<%= @user.name %>になるはずだからデータを表示できるのでは?と思っての記述です。
ちなみにビューの記述はこんな感じです。
<!--ユーザー情報-->
<h2>User info</h2>
<% if book.user %>
<%= image_tag book.user.get_profile_image(100,100) %>
<% else %>
<%= image_tag current_user.get_profile_image(100,100) %>
<% end %>
<table>
<tbody>
<tr>
<th>name</th>
<th>
<% if book.user %>
<%= book.user.name %>
<% else %>
<%= current_user.name %>
<% end %>
</th>
</tr>
<tr>
<th>introduction</th>
<th>
<% if book.user %>
<%= book.user.introduction %>
<% else %>
<%= current_user.introduction %>
<% end %>
</th>
</tr>
</tbody>
</table>
<%= link_to '編集', edit_user_path(current_user.id) %>
<!--投稿フォーム-->
<h2>New book</h2>
<%= form_with model: book do |f| %>
<label for="book_title">Title</label><br>
<%= f.text_field :title,autofocus: true, id: "book_title" %><br>
<label for="book_opinion">Opinion</label><br>
<%= f.text_area :body, id: "book_opinion" %><br>
<%= f.submit 'Create Book' %>
<% end %>
この内容ではエラーになってしまい、どうしてだろうと頭を抱えていました。
調べたりチャットボットに聞いてみたりrenderの部分を書き換えてみたりと試行錯誤しながらも、どうして上手くいかないのか原因が分からず、メンターの方に相談してみることに。
その際、一緒にコードを見てもらいながら直した記述がこちら…、
修正後の記述
def show
@user = User.find(params[:id])
@new_book = Book.new
end
@books = Book.newではnewを作成している変数ということが分かりにくかったので@new_bookに変更します。
<%= render 'books/book', new_book: @new_book, user: @user %>
先ほど「'books.user': @user」と書いていた部分を「user: @user」のようにシンプルにします。
さらに、部分テンプレート内で「books.user」としていた部分を「user」にしました。
<!--ユーザー情報-->
<h2>User info</h2>
<% if user %>
<%= image_tag user.get_profile_image(100,100) %>
<% else %>
<%= image_tag current_user.get_profile_image(100,100) %>
<% end %>
<table>
<tbody>
<tr>
<th>name</th>
<th>
<% if user %>
<%= user.name %>
<% else %>
<%= current_user.name %>
<% end %>
</th>
</tr>
<tr>
<th>introduction</th>
<th>
<% if user %>
<%= user.introduction %>
<% else %>
<%= current_user.introduction %>
<% end %>
</th>
</tr>
</tbody>
</table>
<%= link_to '編集', edit_user_path(current_user.id) %>
<!--投稿フォーム-->
<h2>New book</h2>
<%= form_with model: new_book, url:'/books', method: :post do |f| %>
<label for="book_title">Title</label><br>
<%= f.text_field :title,autofocus: true, id: "book_title" %><br>
<label for="book_opinion">Opinion</label><br>
<%= f.text_area :body, id: "book_opinion" %><br>
<%= f.submit 'Create Book' %>
<% end %>
アドバイスのおかげで、なんとかエラーを回避することが出来ました。
今回のshow以外のビューから呼び出す際の記述の仕方で混乱してしまっていたのですが、そもそも、ユーザー情報と投稿フォームを同じテンプレートにしていたこともややこしくなった原因のひとつでした。
テンプレート1つだけでやりくりしようと思ったのが、今回の一番の失敗ポイントです。
学習を進めながらいろんなコードを見ていると、当時思っていたよりもずっと細かくテンプレートが分かれていて、機能ごとに細かく分ける重要性にも気づけるようになりました。
おわりに
メンターの方にアドバイスをもらいながら修正した際、少し書き換えるだけでコードも圧倒的に視認性が高くなったことに感動しました。
まだまだ改善点はありますが、分かりやすいコードが書けるようにこれからも意識していきたいです。