1 Action Viewについて

Action Viewは、MVCのVに相当し、 Action Controllerと連携してWebリクエストを処理します。Action Controllerは(MVCにおける)モデル層とのやりとりやデータの取得を担当し、次にAction Viewがそのデータを利用してWebリクエストに対するレスポンスのbody(本文)をレンダリングします。

デフォルトのAction Viewテンプレート(単に「ビュー」とも呼ばれます)は、HTMLドキュメント内にRubyコードを記述可能にするERB(Embedded Ruby)で記述します。

Action Viewには、「フォーム」「日付」「文字列」用のHTMLタグを動的に生成するヘルパーメソッドが多数用意されています。必要であれば、アプリケーションに独自のヘルパーを追加することも可能です。

Action Viewでは、コードを簡潔に書けるようにするためにActive Modelのto_paramメソッドやto_partial_pathメソッドを利用しています。ただし、Action ViewがActive Recordに依存しているわけではありません。Action Viewは独立したパッケージであり、任意のRubyライブラリと組み合わせて利用できます。

2 Action ViewをRailsで使う

Action Viewテンプレート(別名「ビュー」)は、app/viewsディレクトリ内のサブディレクトリに保存されます。ここには、コントローラーごとに、コントローラと同じ名前のサブディレクトリがあります。そのサブディレクトリ内にビューファイルが置かれ、コントローラーのアクションへのレスポンスとして特定のビューをレンダリングします。

たとえば、scaffoldでarticleリソースを生成すると、app/views/articlesディレクトリに以下のファイルが生成されます。

$ bin/rails generate scaffold article
      [...]
      invoke  scaffold_controller
      create    app/controllers/articles_controller.rb
      invoke    erb
      create      app/views/articles
      create      app/views/articles/index.html.erb
      create      app/views/articles/edit.html.erb
      create      app/views/articles/show.html.erb
      create      app/views/articles/new.html.erb
      create      app/views/articles/_form.html.erb
      [...]

生成されるファイル名はRailsの命名規約に沿って、対応するコントローラーのアクション名がビューファイル名に取り入れられます(indexアクションに対応するindex.html.erbや、editアクションに対応するedit.html.erbなど)。

この命名規約が守られていれば、Railsがコントローラーのアクションを実行し終わったときに、ユーザーが指定しなくても、そのアクションに対応するビューを自動的に探索してレンダリングします。たとえば、articles_controller.rbindexアクションを実行すると、app/views/articles/ディレクトリ内のindex.html.erbビューを自動的にレンダリングします。そのためには、ファイル名と置き場所の両方が規約に沿っていることが重要です。

クライアント(ブラウザ)に返される最終的なHTMLは、「ERB」ファイル(拡張子は.html.erb)、それをラップする「レイアウトテンプレート」、ERBファイルが参照するすべての「パーシャル」ファイル(部分テンプレートとも)の組み合わせで構成されます。本ガイドでは、この後「テンプレート」、「パーシャル」、「レイアウト」という3つのコンポーネントについてそれぞれ詳しく説明します。

3 テンプレート

Action Viewテンプレートは、さまざまなフォーマットで記述できます。 テンプレートファイルの拡張子が.erbの場合は、HTMLレスポンスのビルドにERBが使われます。 テンプレートファイルの拡張子が.jbuilderの場合は、JSONレスポンスのビルドにJbuilder gemが使われます。 テンプレートファイルの拡張子が.builderの場合は、XMLレスポンスのビルドにBuilder::XmlMarkupライブラリが使われます。

Railsは、複数のテンプレートシステムをファイル拡張子で区別します。 たとえば、ERBテンプレートシステムを用いるHTMLファイルのファイル拡張子は.html.erb、Jbuilderテンプレートシステムを用いるJSONファイルのファイル拡張子は.json.jbuilderになります。他のテンプレートライブラリを利用すると、これ以外のテンプレート種別やファイル拡張子も追加される場合があります。

3.1 ERB

ERBテンプレートの内部では、<% %>タグや<%= %>タグの中にRubyコードを書けます。 最初の<% %>タグはその中に書かれたRubyコードを実行しますが、実行結果はレンダリングされません。条件文やループ、ブロックなどレンダリングの不要な行はこのタグの中に書くとよいでしょう。 次の<%= %>タグでは実行結果がWebページにレンダリングされます。

以下は、名前をレンダリングするためのループです。

ERBテンプレートは、<% %><%= %>などの特殊なERBタグを利用して、Rubyコードを静的HTML内に埋め込む形で記述する方法です。

拡張子が.html.erbであるERBビューテンプレートをRailsが処理すると、ERB内のRubyコードが評価され、ERBタグを動的な出力に置き換えます。生成された動的コンテンツは静的なHTMLマークアップと結合されて、最終的なHTMLレスポンスが完成します。

ERBテンプレート内には、<% %>タグや<%= %>タグでRubyコードを記述できます。 <% %>タグ(=を含まない)は、実行結果を出力せずにRubyコードを実行したい場合に使います(条件やループなど)。 <%= %>タグ(=を含む)は、Rubyコードの実行結果を出力してテンプレート内でレンダリングしたい場合に使います(以下のコード例のperson.nameモデル属性など)。

<h1>Names</h1>
<% @people.each do |person| %>
  Name: <%= person.name %><br>
<% end %>

ループの開始行と終了行は通常のERBタグ(<% %>)に書かれており、名前をレンダリングする行はレンダリング用のERBタグ(<%= %>)に書かれています。

上のコードは、単にERBの書き方を説明しているだけではありません。Rubyでよく使われるprintputsのような通常のレンダリング関数は、ERBでは利用できませんのでご注意ください。たとえば以下のコードを書いても、ブラウザに"Frodo"は表示されません。

<%# 以下のコードは無効 %>
Hi, Mr. <% puts "Frodo" %>

なお、ERBには上のように<%# %>でコメントを書くことも可能です。

Webページへのレンダリング結果の冒頭と末尾からホワイトスペースを取り除きたい場合は、通常の<% %>の代わりに<%- -%>を利用できます(訳注: これは英語のようなスペース分かち書きを行なう言語向けのノウハウです)。

3.2 Jbuilder

JbuilderはRailsチームによってメンテナンスされているgemの1つで、RailsのGemfileにデフォルトで含まれています。JbuilderはJSONレスポンスをビューテンプレートで生成するのに使われます。

Jbuilderが導入されていない場合は、Gemfileに以下を追加できます。

gem 'jbuilder'

拡張子が.jbuilderのテンプレートでは、jsonという名前のJbuilderオブジェクトが自動的に利用可能になります。

基本的な例を以下に示します。

json.name("Alex")
json.email("alex@example.com")

上のコードから以下のJSONが生成されます。

{
  "name": "Alex",
  "email": "alex@example.com"
}

詳しいコード例についてはJbuilderドキュメントを参照してください。

3.3 Builder

BuilderテンプレートはERBの代わりに利用できる、よりプログラミング向きな記法です。これはJBuilderに似ていますが、JSONではなくXMLを生成するのに使われます。

拡張子が.builderのテンプレートでは、xmlという名前のXmlMarkupオブジェクトが自動的に利用可能になります。

基本的な例を以下に示します。

xml.em("emphasized")
xml.em { xml.b("emph & bold") }
xml.a("A Link", "href" => "https://rubyonrails.org")
xml.target("name" => "compile", "option" => "fast")

上のコードから以下が生成されます。

<em>emphasized</em>
<em><b>emph &amp; bold</b></em>
<a href="https://rubyonrails.org">A link</a>
<target option="fast" name="compile" />

ブロックを渡されたメソッドはすべて、ブロックの中にネストしたマークアップを含むXMLマークアップタグとして扱われます。以下の例で示します。

xml.div {
  xml.h1(@person.name)
  xml.p(@person.bio)
}

上のコードの出力は以下のようになります。

<div>
  <h1>David Heinemeier Hansson</h1>
  <p>A product of Danish Design during the Winter of '79...</p>
</div>

詳しいコード例についてはBuilderドキュメントを参照してください。

3.4 テンプレートをコンパイルする

Railsは、デフォルトでビューの各テンプレートをコンパイルしてレンダリング用メソッドにします。developmentモードの場合、ビューテンプレートが変更されるとファイルの更新日時で変更が検出され、再コンパイルされます。

ページのさまざまな部分を個別にキャッシュしたりキャッシュを失効させたりする必要がある場合には、フラグメントキャッシュも利用できます。詳しくはキャッシュガイドを参照してください。

4 パーシャル

パーシャル(部分テンプレート)は、ビューテンプレートを再利用可能な小さい部品に分割する方法です。パーシャルを利用することで、メインテンプレートのコードの一部を別の小さなファイルに抽出し、そのファイルをメインテンプレートでレンダリングできます。メインテンプレートからパーシャルファイルにデータを渡すことも可能です。

いくつかの例で実際の動作を見てみましょう。

4.1 パーシャルをレンダリングする

パーシャルをビューの一部に含めてレンダリングするには、ビューで以下のようにrenderメソッドを使います。

<%= render "product" %>

上の呼び出しによって、_product.html.erbという名前のファイルが同じフォルダ内で検索され、そのビュー内でレンダリングされます。パーシャルファイル名の冒頭は、規約によりアンダースコア_で始まるので、パーシャルビューと通常のビューはファイル名で区別できます。ただし、レンダリングするパーシャルをビュー内で参照するときは、パーシャル名にアンダースコア_を追加せずに参照することにご注意ください。これは、以下のように別のディレクトリにあるパーシャルを参照する場合も同様です。

<%= render "application/product" %>

上のコードは、その位置にapp/views/application/_product.html.erbパーシャルを読み込みます。

4.2 パーシャルを活用してビューを簡潔に保つ

すぐに思い付くパーシャルの利用法のひとつが、パーシャルをサブルーチンと同等とみなすという方法です。ビューの詳細部分をパーシャルに移動し、コードの見通しを良くするためにパーシャルを使うのです。たとえば、以下のようなビューがあるとします。

<%= render "application/ad_banner" %>

<h1>Products</h1>

<p>私たちの素晴らしい製品のいくつかをご紹介します:</p>
<% @products.each do |product| %>
  <%= render partial: "product", locals: { product: product } %>
<% end %>

<%= render "application/footer" %>

上のコード例にある_ad_banner.html.erbパーシャルと_footer.html.erbパーシャルに含まれるコンテンツは、アプリケーション内のさまざまなページと共有できます。この"Products"ページの開発中は、パーシャルの細かな表示内容を気にせずに済みます。

上のコード例では、_product.html.erbパーシャルも使われています。このパーシャルには、個別の製品をレンダリングするための詳細なコードが含まれていて、@productsコレクション内にある個別の製品をリスト化してレンダリングするのに使われます。

5 パーシャルにlocalsオプションでデータを渡す

あるビュー内でパーシャルをレンダリングするときに、パーシャルにデータを引数のように渡すことが可能です。パーシャルに渡すデータは、locals:オプションにハッシュの形で渡します。locals:オプションに渡したハッシュの各キーは、パーシャル内でローカル変数として参照可能になります。

<%# app/views/products/show.html.erb %>

<%= render partial: "product", locals: { my_product: @product } %>
<%# app/views/products/_product.html.erb %>

<%= tag.div id: dom_id(my_product) do %>
  <h1><%= my_product.name %></h1>
<% end %>

「パーシャルローカル変数」とは、指定のパーシャル内のローカル変数、つまりそのパーシャル内でのみ利用可能な変数です。上のコード例では、my_productがパーシャルローカル変数であり、元のビューからパーシャルに渡されたときに、@productインスタンス変数の値がmy_productに割り当てられたものです。

なお、このコード例では説明上インスタンス変数名やテンプレート名と一時的に区別するためにローカル変数名をあえてmy_productとしていますが、実際のコードではmy_などを付けずにインスタンス変数と一貫するproductというローカル変数を使う方が一般的である点にご注意ください。

localsはハッシュなので、必要に応じてlocals: { my_product: @product, my_reviews: @reviews }のように複数の変数を渡すことも可能です。

ただし、locals:オプションの一部としてビューに渡していない変数がテンプレート内で参照されると、ActionView::Template::Errorが発生します。

<%# app/views/products/_product.html.erb %>

<%= tag.div id: dom_id(my_product) do %>
  <h1><%= my_product.name %></h1>

  <%# `product_reviews`は存在しないのでActionView::Template::Errorになる %>
  <% product_reviews.each do |review| %>
    <%# ... %>
  <% end %>
<% end %>

5.1 local_assignsを使う

個別のパーシャル内ではlocal_assignsというメソッドが利用可能です。このメソッドを用いると、locals:オプション経由で渡されたキーにアクセスできます。パーシャルがレンダリングされるときに:some_keyが未設定の場合、パーシャル内の local_assigns[:some_key]の値はnilになります。

たとえば、以下のコード例のproduct_reviewsnilになります。これは、locals:に設定されているのがproductだけであるためです。

<%# app/views/products/show.html.erb %>

<%= render partial: "product", locals: { product: @product } %>

<%# app/views/products/_product.html.erb %>

<% local_assigns[:product]          # => "#<Product:0x0000000109ec5d10>" %>
<% local_assigns[:product_reviews]  # => nil %>

local_assignsのユースケースの1つは、ローカル変数をオプションとしてパーシャルに渡し、以下のようにローカル変数に値が設定済みかどうか基づいて条件付きで何らかの操作をパーシャル内で実行するというものです。

<% if local_assigns[:redirect] %>
  <%= form.hidden_field :redirect, value: true %>
<% end %>

別の例として、Active Storageの_blob.html.erbのコードを引用します。このコードは、この行を含むパーシャルをレンダリングするときにin_galleryローカル変数が設定されているかどうかに基づいて表示サイズを設定します。

<%= image_tag blob.representation(resize_to_limit: local_assigns[:in_gallery] ? [ 800, 600 ] : [ 1024, 768 ]) %>

5.2 partiallocalsオプションを指定しないrender

上の例では、renderpartiallocalsという2つのオプションを渡しましたが、渡したいオプションが他にない場合は、これらのオプションのキー名を省略して値だけを渡すことも可能です。

次の例で説明します。

<%= render partial: "product", locals: { product: @product } %>

上のコードは以下のように値だけを渡す形でも書けます。

<%= render "product", product: @product %>

上のコードは、パーシャル名とローカル変数名とインスタンス変数名が同じなので、以下のようにRailsの規約に沿った省略形でも書けます。

<%= render @product %>

この場合、app/views/products/ディレクトリ内で_product.html.erbというパーシャルを探索し、productというパーシャルローカル変数に@productインスタンス変数を設定します。

5.3 asオプションとobjectオプション

ActionView::Partials::PartialRendererは、デフォルトでテンプレートと同じ名前のローカル変数内に自身のオブジェクトを保持します。以下のコードを見てみましょう。

<%= render @product %>

上のコードでは、_productパーシャル内でローカル変数productから@productを取得できます。これは以下のコードと同等の結果になります。

<%= render partial: "product", locals: { product: @product } %>

objectオプションは、パーシャルで出力するオブジェクトを直接指定したい場合に使います。これは、テンプレートのオブジェクトが他の場所(別のインスタンス変数や別のローカル変数など)にある場合に便利です。

たとえば、以下のコードがあるとします。

<%= render partial: "product", locals: { product: @item } %>

上のコードは以下のように書けます。

<%= render partial: "product", object: @item %>

ここでは、@itemインスタンス変数がproductという名前のパーシャルローカル変数に割り当てられます。

ローカル変数名をデフォルトのproductから別の名前に変更したい場合は、:as オプションが使えます。 asオプションを使うと、以下のようにローカル変数に別の名前を指定できます。

<%= render partial: "product", object: @item, as: "item" %>

上は以下と同等です。

<%= render partial: "product", locals: { item: @item } %>

5.4 コレクションをレンダリングする

ビューで@productsなどのコレクションをイテレーションして、コレクション内のオブジェクトごとにパーシャルテンプレートをレンダリングするという方法は一般によく使われます。このパターンは、配列を受け取って、配列内の要素ごとにパーシャルをレンダリングする単一のメソッドとしてRailsに実装済みです。

すべての製品(products)を出力するコード例は以下のようになります。

<% @products.each do |product| %>
  <%= render partial: "product", locals: { product: product } %>
<% end %>

上のコードは以下のように1行で書けます。

<%= render partial: "product", collection: @products %>

パーシャルにコレクションを渡して呼び出すと、パーシャルの個別のインスタンスは、そのパーシャル名に沿った変数を介して、レンダリングするコレクションのメンバーにアクセスできるようになります。この場合、パーシャルは_product.html.erbというファイルなので、レンダリングするコレクションのメンバーにproductという名前のローカル変数名で参照できます。

コレクションをレンダリングするために、Railsの規約に基づいた以下の省略形構文も利用できます。

<%= render @products %>

上のコード例では、@productsインスタンス変数がProductインスタンスのコレクションであることが前提です。 Railsはコレクション内のモデル名(この場合はProduct)を命名規約に沿って調べることで、利用するパーシャル名を決定します。

実は、この省略表現を使うと、コレクションがさまざまなモデルのインスタンスで構成されていてもレンダリング可能になります。Rails は、コレクションの各メンバーに適したパーシャルを選択します。

5.5 スペーサーテンプレート

:spacer_templateオプションを使うと、メインのパーシャルの間を埋める第2のパーシャルを指定できます。

<%= render partial: @products, spacer_template: "product_ruler" %>

上のコードは、メインの_productパーシャル同士の空きを調整するスペーサーとなる_product_rulerパーシャルをレンダリングします(_product_rulerにはデータを渡していません)。

5.6 カウンタ変数

Railsでは、コレクションによって呼び出されるパーシャル内でカウンタ変数も利用可能です。カウンタ変数名は、パーシャル名の後ろに_counterを追加したものになります。たとえば、@productsコレクションをレンダリングする場合、_product.html.erbパーシャルでproduct_counter変数にアクセスできます。このカウンタ変数は、最初のレンダリング時点の値が0から始まり、パーシャルの外側のビュー内でパーシャルがレンダリングされた回数を参照します。

<%# index.html.erb %>
<%= render partial: "product", collection: @products %>
<%# _product.html.erb %>
<%= product_counter %> # 1個目のproductは0、2個目のproductは1...

カウンタ変数は、as:オプションで名前が変更されたローカル変数でも利用できます。つまり、as: :itemを指定すると、カウンタ変数はitem_counterになります。

後述する2つのセクション厳密なlocalslocal_assignsでパターンマッチングを活用するでは、より高度なパーシャルの利用法が説明されていますが、完全を期すためにここでも記載します。

5.7 local_assignsでパターンマッチングを活用する

local_assignsHashなので、Ruby 3.1のパターンマッチング代入演算子と互換性があります。

local_assigns => { product:, **options }
product # => "#<Product:0x0000000109ec5d10>"
options # => {}

パーシャルローカル変数に:product以外のキーを複数持つHashを代入する場合、以下のようにsplat演算子**でヘルパーメソッド呼び出しに展開して渡すことが可能です。

<%# app/views/products/_product.html.erb %>

<% local_assigns => { product:, **options } %>

<%= tag.div id: dom_id(product), **options do %>
  <h1><%= product.name %></h1>
<% end %>
<%# app/views/products/show.html.erb %>

<%= render "products/product", product: @product, class: "card" %>
<%# => <div id="product_1" class="card">
  #      <h1>A widget</h1>
  #    </div>
%>

パターンマッチングの代入では、変数のリネームもサポートされます。

local_assigns => { product: record }
product             # => "#<Product:0x0000000109ec5d10>"
record              # => "#<Product:0x0000000109ec5d10>"
product == record   # => true

local_assignsfetchを使うと、以下のように変数を条件付きで読み取り、キーがlocals:オプションに含まれていない場合にデフォルト値にフォールバックすることも可能です。

<%# app/views/products/_product.html.erb %>

<% local_assigns.fetch(:related_products, []).each do |related_product| %>
  <%# ... %>
<% end %>

Ruby 3.1のパターンマッチング代入演算子にHash#with_defaults呼び出しを組み合わせると、パーシャルローカル変数のデフォルト値代入を以下のようにコンパクトに書けます。

<%# app/views/products/_product.html.erb %>

<% local_assigns.with_defaults(related_products: []) => { product:, related_products: } %>

<%= tag.div id: dom_id(product) do %>
  <h1><%= product.name %></h1>

  <% related_products.each do |related_product| %>
    <%# ... %>
  <% end %>
<% end %>

5.8 厳密なlocals

Action Viewのパーシャルは、内部で通常のRubyメソッドにコンパイルされます。 Rubyではローカル変数を動的に作成できないため、パーシャルに渡されるlocalsの組み合わせが一定していないと、組み合わせごとに別のバージョンをコンパイルする必要が生じます。

<%# app/views/articles/show.html.erb %>
<%= render partial: "article", layout: "box", locals: { article: @article } %>
<%= render partial: "article", layout: "box", locals: { article: @article, theme: "dark" } %>

上のスニペットではパーシャルのコンパイルが2回も行われているため、時間とメモリがその分消費されてしまいます。

def _render_template_2323231_article_show(buffer, local_assigns, article:)
  # ...
end

def _render_template_3243454_article_show(buffer, local_assigns, article:, theme:)
  # ...
end

組み合わせの数が少ないうちはそれほど問題にはなりませんが、組み合わせの数が増えるに連れて、かなりの量のメモリが浪費され、コンパイルに長時間かかるようになります。この問題に対処するには、「厳密なlocals」(strict locals)という一種のアノテーション機能を用いて、コンパイル済みパーシャルのシグネチャを定義することで、コンパイルされるパーシャルのバージョンが1種類だけになるようにします。

<%# locals: (article:, theme: "light") -%>
...

locals:シグネチャでは上のように、Rubyのメソッドシグネチャと同じ構文を利用して、パーシャルにどのローカル変数を何個渡せるかを強制することも、デフォルト値を設定することもできます。

locals:シグネチャの例をいくつか示します。

<%# app/views/messages/_message.html.erb %>

<%# locals: (message:) -%>
<%= message %>

上のコード例では、messageローカル変数が必須になり、パーシャルを呼び出すときに省略できなくなります。引数に:messageローカル変数を渡さずにこのパーシャルをレンダリングすると、以下のように例外が発生します。

render "messages/message"
# => ActionView::Template::Error: missing local: :message for app/views/messages/_message.html.erb

以下のようにmessageにデフォルト値を設定しておくと、messageが渡されない場合にそのデフォルト値が使われます。

<%# app/views/messages/_message.html.erb %>

<%# locals: (message: "Hello, world!") -%>
<%= message %>

上のパーシャルに:messageローカル変数を渡さずにレンダリングすると、locals:シグネチャで設定したデフォルト値が使われます。

render "messages/message"
# => "Hello, world!"

これも同様に、local:シグネチャで許可されていないローカル変数を渡してパーシャルをレンダリングすると、例外が発生します。

render "messages/message", unknown_local: "will raise"
# => ActionView::Template::Error: unknown local: :unknown_local for app/views/messages/_message.html.erb

以下のようにdouble splat演算子**も併用すると、省略可能なオプションローカル変数も引数として渡せるようになります。


<%# app/views/messages/_message.html.erb %>

<%# locals: (message: "Hello, world!", **attributes) -%>
<%= tag.p(message, **attributes) %>

逆に、以下のようにlocals: ()を設定すると、localsを完全に無効にできます。

<%# app/views/messages/_message.html.erb %>

<%# locals: () %>

上のコード例では、パーシャルにどんなローカル変数を渡しても以下のように例外が発生します。

render "messages/message", unknown_local: "will raise"
# => ActionView::Template::Error: no locals accepted for app/views/messages/_message.html.erb

Action Viewは、#で始まるコメント文をサポートする任意のテンプレートエンジンでlocals:シグネチャを処理します。このシグネチャは、パーシャル内のどの行に書かれていても認識されます。

サポートされているのはキーワード引数のみです。位置引数やブロック引数が使われると、レンダリング時にAction Viewエラーが発生します。

local_assignsメソッドには、local:マジックコメントで指定したデフォルト値は含まれない点にご注意ください。Rubyの予約キーワード(classifなど)と同じ名前のデフォルト値を持つローカル変数にアクセスするには、以下のようにbinding.local_variable_getで値にアクセスできます。

<%# locals: (class: "message") %>
<div class="<%= binding.local_variable_get(:class) %>">...</div>

5.9 レイアウト

レイアウト(layout)を使うと、Railsのさまざまなコントローラアクションの結果を共通のビューテンプレートでレンダリングできます。Railsアプリケーションでは、ページのレンダリングに複数のレイアウトを利用可能です。

たとえば、あるアプリケーションでは、ユーザーログインページでログインに適したレイアウトを利用し、マーケティングやセールス用ページではそれに適した別のレイアウトを利用できます。ログインしたユーザー向けのレイアウトであれば、ナビゲーションツールバーをページのトップレベルに表示するスタイルを多くのコントローラやアクションで共通化することも可能です。SaaSアプリケーションの商品販売用レイアウトであれば、トップレベルのナビゲーションに「お値段」や「お問い合わせ先」を共通して表示できます。また、レイアウトごとにヘッダーやフッターのコンテンツを変更することも可能です。

Railsでは、現在のコントローラアクションに対応するレイアウトを探索するために、最初にコントローラと同じベース名を持つファイルをapp/views/layoutsディレクトリ内で探します。たとえば、ProductsControllerクラスのアクションをレンダリングする場合、app/views/layouts/products.html.erbが使われます。

コントローラに対応するレイアウトが存在しない場合は、app/views/layouts/application.html.erb

以下は、application.html.erbファイルのシンプルなレイアウトの例です。

<!DOCTYPE html>
<html>
<head>
  <title><%= "Your Rails App" %></title>
  <%= csrf_meta_tags %>
  <%= csp_meta_tag %>
  <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
  <%= javascript_importmap_tags %>
</head>
<body>

<nav>
  <ul>
    <li><%= link_to "Home", root_path %></li>
    <li><%= link_to "Products", products_path %></li>
    <!-- Additional navigation links here -->
  </ul>
</nav>

<%= yield %>

<footer>
  <p>&copy; <%= Date.current.year %> Your Company</p>
</footer>

上のレイアウト例では、<%= yield %>の部分でビューコンテンツがレンダリングされ、それが<head><nav><footer>のコンテンツで囲まれる形になります。

Railsには、個別のコントローラアクションに対応するレイアウトを割り当てるためのさまざまな方法が用意されています。Railsのレイアウトについて詳しくは、ビューのレイアウトとレンダリングガイドを参照してください。

5.10 パーシャルレイアウト

パーシャルにも独自のレイアウトを適用できます。パーシャル用のレイアウトは、アクション全体にわたるグローバルなレイアウトとは異なりますが、同じように動作します。

試しに、ページ上に投稿を1つ表示してみましょう。表示制御のためdivタグで囲むことにします。最初に、Articleを1つ新規作成します。

Article.create(body: "パーシャルレイアウトはいいぞ!")

showテンプレートは、boxレイアウトで囲まれた_articleパーシャルを出力します。

articles/show.html.erb

<%= render partial: 'article', layout: 'box', locals: { article: @article } %>

boxレイアウトは、divタグで_articleパーシャルを囲んだ簡単な構造です。

articles/_box.html.erb

<div class="box">
  <%= yield %>
</div>

この例では、パーシャルレイアウト_box.html.erb内でarticleローカル変数が使われていないにもかかわらず、render呼び出しに渡されたarticleローカル変数にアクセスできる点にご注目ください。

アプリケーション共通のレイアウトを参照する場合とは異なり、パーシャルレイアウトを参照するときはアンダースコア_を付ける点にご注意ください。

yieldを呼び出す代わりに、パーシャルレイアウト内にあるコードのブロックをレンダリングすることも可能です。たとえば、_articleというパーシャルがない場合でも、以下のような呼び出しが行えます。

<%= render(layout: 'box', locals: { article: @article }) do %>
  <div>
    <p><%= article.body %></p>
  </div>
<% end %>

ここでも同じ_boxパーシャルを使っていれば、上述の例と同じ出力が得られます。

5.11 コレクションでパーシャルレイアウトを利用する

コレクションをレンダリングする場合、パーシャルレイアウトに:layoutオプションを指定することも可能です。

<%= render partial: "article", collection: @articles, layout: "special_layout" %>

コレクション内の各アイテムに対してパーシャルをレンダリングするときに、このレイアウトもレンダリングされます。現在のオブジェクト(articleなど)やオブジェクトのカウンタ変数(article_counterなど)は、パーシャル内の場合と同様にレイアウト内でも利用可能です。

6 ヘルパー

Railsでは、Action Viewで利用できるヘルパーメソッドを多数提供しています。ヘルパーメソッドには以下のものが含まれます。

  • 日付・文字列・数値のフォーマット
  • 画像・動画・スタイルシートなどへのHTMLリンク作成
  • コンテンツのサニタイズ
  • フォームの作成
  • コンテンツのローカライズ

ヘルパーについて詳しくは、ガイドのAction View ヘルパーおよびAction View フォームヘルパーを参照してください。

7 ローカライズされたビュー

Action Viewは、現在のロケールに応じてさまざまなテンプレートをレンダリングできます。

たとえば、ArticlesControllershowアクションがあるとします。このshowアクションを呼び出すと、デフォルトではapp/views/articles/show.html.erbが出力されます。ここでI18n.locale = :deを設定すると、代わりにapp/views/articles/show.de.html.erbがレンダリングされます。ローカライズ版のテンプレートが見当たらない場合は、装飾なしのバージョンが使われます。つまり、ローカライズ版ビューがなくても動作しますが、ローカライズ版ビューがあればそれが使われます。

同じ要領で、publicディレクトリのレスキューファイル (いわゆるエラーページ) もローカライズできます。たとえば、I18n.locale = :deと設定し、public/500.de.htmlpublic/404.de.htmlを作成することで、ローカライズ版のレスキューページを作成できます。

詳しくはRails 国際化 (i18n) API を参照してください。

フィードバックについて

Railsガイドは GitHub の yasslab/railsguides.jp で管理・公開されております。本ガイドを読んで気になる文章や間違ったコードを見かけたら、気軽に Pull Request を出して頂けると嬉しいです。Pull Request の送り方については GitHub の README をご参照ください。

原著における間違いを見つけたら『Rails のドキュメントに貢献する』を参考にしながらぜひ Rails コミュニティに貢献してみてください 🛠💨✨

本ガイドの品質向上に向けて、皆さまのご協力が得られれば嬉しいです。

Railsガイド運営チーム (@RailsGuidesJP)

支援・協賛

Railsガイドは下記の協賛企業から継続的な支援を受けています。支援・協賛にご興味あれば協賛プランからお問い合わせいただけると嬉しいです。

  1. Star
  2. このエントリーをはてなブックマークに追加