【Rails】ビューファイルのパーシャルにはローカル変数で値を渡すべき

パーシャルを使ってビューファイルを共通化する際にlocals オプションを使うべきなのか分からなかったので調べてみました。

結論

パーシャルにはlocals オプションを使ってローカル変数で値を渡した方が良い。

partialは呼び出し元のテンプレートとだけ紐づけておくようにしたほうがいい。 インスタンス変数を使うと、コントローラとも結びついてしまい、結果としてpartialとして切り出したのに再利用性が低くなる。

partialではインスタンス変数で値を渡すを参照しない方がいい - qiita

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

パーシャルでインスタンス変数を使わない方が良いと考える主な理由は「変数の影響範囲が広くなってしまう」ことのようです。具体的には次のようなことが考えられます。

  • コントローラーの変更に伴ってパーシャルの変更も必要になってしまう
  • モデルのデータへの依存度が高くなり柔軟性が無くなる
  • パーシャルにローカル変数を使う事で再利用時に修正範囲が狭くて済む

パーシャルへの値の受け渡しはできるだけローカル変数を使った方が良さそうです。

注意点

パーシャルにローカル変数を使って値を渡す場合は次の2つに注意してください。

1. locals: を明記する場合はpartial: も一緒に明記する必要がある

locals: を明記する場合はpartial: も一緒に明記しなければエラー(undefined local variable or method)が発生します。 locals:partial: と一緒に書くか、もしくは両方とも省略するのが正しい記述のようです。

# locals:を明記するにはpartial:の明記も必要
<%= render partial: "product", locals: { product: @product } %>

# locals:を省略するならpartial:も省略すればok
<%= render "product", product: @product %>

Action View の概要 - Railsガイド

2. パーシャルからパーシャルへはローカル変数は引き継がれない

ローカル変数なのでパーシャルからパーシャルへ値を引き継ぐ(渡す)ことはできません。 パーシャルからパーシャルを呼び出す際にローカル変数の値を渡したい場合はobject オプションを使うと良いようです。 locals オプションと同様にローカル変数をパーシャルに渡すことができます。 また、as オプションを併用するを使うことでローカル変数名を指定することも可能です。

# localsオプションでインスタンス変数@itemをローカル変数productとしてパーシャルに渡す
<%= render partial: "product", locals: { product: @item } %>

# objectオプションでインスタンス変数@itemをローカル変数itemとしてパーシャルに渡す
<%= render partial: "product", object: @item %>

# object + asオプションでインスタンス変数@itemをローカル変数名をitemに指定する(↑と同等)
<%= render partial: "product", object: @item, as: "item" %>

Action View の概要 - Railsガイド

実装例

app/views/users/index.html.erbapp/views/users/followers.html.erb の共通項をapp/views/users/_list.html.erb パーシャルを使って共通化したい。

# app/contollers/users_controller.rb

  def index
    @users = 全ユーザーの取得処理
  end

  def followers
    @followers = フォロワーの取得処理
  end
# app/views/users/index.html.erb

<h1>Index</h1>

# インスタンス変数@usersをローカル変数userでパーシャルに渡す
<%= render partial: "list", locals: { users: @users } %>
# app/views/users/followers.html.erb

<h1>Followers</h1>

# インスタンス変数@followersをローカル変数userでパーシャルに渡す
<%= render partial: "list", locals: { users: @followers } %>
# app/views/users/_list.html.erb

# 渡ってきたローカル変数usersを使って表示部を共通化する
<% users.each do |user| %>
    <%= user.email %>
    <%= user.name %>
    <%= link_to "#{user.nama}の詳細", user_path(user) %>
<% end %>

まとめ

パーシャルへの値の渡し方とlocals オプションの使い方が理解できたのでスッキリ。 FBCRailsのプラクティスも残り少ないのでしっかり学んでいきたい。

参照

Action View の概要 - Railsガイド

partialではインスタンス変数で値を渡すを参照しない方がいい - qiita

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