edge
詳細はrubyonrails.orgで: もっとRuby on Rails

Action Viewの概要

このガイドを読むことで、以下のことがわかります:

1 Action Viewとは何ですか?

Railsでは、WebリクエストはAction ControllerとAction Viewによって処理されます。通常、Action Controllerはデータベースとの通信や必要な場合のCRUDアクションに関わります。その後、Action Viewがレスポンスをコンパイルする責任を持ちます。

Action Viewのテンプレートは、HTMLと組み合わせた埋め込みRubyを使用して書かれます。テンプレートを冗長なコードで混雑させないために、いくつかのヘルパークラスがフォーム、日付、文字列などの共通の動作を提供します。また、アプリケーションが進化するにつれて新しいヘルパーを簡単に追加することもできます。

注意:Action Viewの一部の機能はActive Recordに関連していますが、それはAction ViewがActive Recordに依存していることを意味するものではありません。Action Viewは独立したパッケージであり、どのような種類のRubyライブラリとも使用することができます。

2 RailsでAction Viewを使用する方法

各コントローラには、app/viewsディレクトリに関連付けられたディレクトリがあり、そのコントローラに関連するビューを構成するテンプレートファイルが格納されています。これらのファイルは、各コントローラアクションから結果として表示されるビューを表示するために使用されます。

scaffoldジェネレータを使用して新しいリソースを作成する場合、Railsがデフォルトで行う動作を見てみましょう:

$ 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では、ビューには命名規則があります。通常、ビューは関連するコントローラアクションと同じ名前を共有します。上記の例では、articles_controller.rbのindexコントローラアクションは、app/views/articlesディレクトリのindex.html.erbビューファイルを使用します。クライアントに返される完全なHTMLは、このERBファイル、それを囲むレイアウトテンプレート、およびビューが参照するすべてのパーシャルの組み合わせで構成されます。このガイドでは、これらの3つのコンポーネントについての詳細なドキュメントを見つけることができます。

前述のように、最終的なHTML出力は3つのRails要素(テンプレート、パーシャル、レイアウト)の組み合わせです。 以下にそれぞれの概要を示します。

3 テンプレート

Action Viewのテンプレートは、いくつかの方法で書くことができます。テンプレートファイルの拡張子が.erbの場合、ERB(埋め込みRuby)とHTMLの組み合わせが使用されます。テンプレートファイルの拡張子が.builderの場合、Builder::XmlMarkupライブラリが使用されます。

Railsは複数のテンプレートシステムをサポートし、ファイルの拡張子を使用してそれらを区別します。たとえば、ERBテンプレートシステムを使用したHTMLファイルの拡張子は.html.erbになります。

3.1 ERB

ERBテンプレート内では、<% %><%= %>のタグを使用してRubyコードを含めることができます。<% %>タグは、条件やループ、ブロックなど、何も返さないRubyコードを実行するために使用され、<%= %>タグは出力が必要な場合に使用されます。

次の名前のループを考えてみましょう:

<h1>全ての人の名前</h1>
<% @people.each do |person| %>
  名前: <%= person.name %><br>
<% end %>

このループは通常の埋め込みタグ(<% %>)を使用して設定され、名前は出力埋め込みタグ(<%= %>)を使用して挿入されます。なお、これは単なる使用の提案ではありません:printputsなどの通常の出力関数は、ERBテンプレートではビューにレンダリングされません。したがって、次のようになります:

<%# 間違い %>
こんにちは、Mr. <% puts "Frodo" %>

先頭と末尾の空白を抑制するには、<%- -%><%%>と交換可能に使用することができます。

3.2 Builder

Builderテンプレートは、ERBに対するよりプログラム的な代替手段です。特に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マークアップタグとして扱われます。たとえば、次のようなものです: ruby 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>

以下は実際にBasecampで使用された完全なRSSの例です:

xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
  xml.channel do
    xml.title(@feed_title)
    xml.link(@url)
    xml.description "Basecamp: Recent items"
    xml.language "en-us"
    xml.ttl "40"

    for item in @recent_items
      xml.item do
        xml.title(item_title(item))
        xml.description(item_description(item)) if item_description(item)
        xml.pubDate(item_pubDate(item))
        xml.guid(@person.firm.account.url + @recent_items.url(item))
        xml.link(@person.firm.account.url + @recent_items.url(item))
        xml.tag!("dc:creator", item.author_name) if item_has_creator?(item)
      end
    end
  end
end

3.3 Jbuilder

Jbuilderは、Railsチームによってメンテナンスされ、デフォルトのRails Gemfileに含まれているgemです。Builderと似ていますが、XMLの代わりにJSONを生成するために使用されます。

持っていない場合は、Gemfileに次の行を追加できます:

gem 'jbuilder'

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

以下は基本的な例です:

json.name("Alex")
json.email("[email protected]")

これにより、次のような出力が生成されます:

{
  "name": "Alex",
  "email": "[email protected]"
}

詳細な例や情報については、Jbuilderのドキュメントを参照してください。

3.4 テンプレートキャッシュ

デフォルトでは、Railsは各テンプレートをレンダリングするためのメソッドにコンパイルします。開発環境では、テンプレートを変更すると、Railsはファイルの変更時刻を確認して再コンパイルします。

4 パーシャル

パーシャルテンプレート(通常は「パーシャル」と呼ばれる)は、レンダリングプロセスをより管理しやすいチャンクに分割するための別のデバイスです。パーシャルを使用すると、テンプレートからコードの一部を別のファイルに抽出し、テンプレート全体で再利用することができます。

4.1 パーシャルのレンダリング

ビューの一部としてパーシャルをレンダリングするには、ビュー内でrenderメソッドを使用します:

<%= render "menu" %>

これにより、レンダリングされているビューのそのポイントで_menu.html.erbというファイルがレンダリングされます。先頭にアンダースコアが付いていることに注意してください:パーシャルは通常のビューと区別するために先頭にアンダースコアが付けられていますが、参照する際にはアンダースコアなしで指定されます。これは、別のフォルダからパーシャルを取り込む場合でも同様です:

<%= render "shared/menu" %>

このコードは、app/views/shared/_menu.html.erbからパーシャルを取り込みます。

4.2 パーシャルを使用してビューを簡素化する

パーシャルを使用する方法の1つは、それらをサブルーチンのように扱うことです。つまり、ビューから詳細を切り出して、何が起こっているかをより簡単に把握できるようにする方法です。たとえば、次のようなビューがあるかもしれません:

<%= render "shared/ad_banner" %>

<h1>Products</h1>

<p>Here are a few of our fine products:</p>
<% @products.each do |product| %>
  <%= render partial: "product", locals: { product: product } %>
<% end %>

<%= render "shared/footer" %>

ここでは、_ad_banner.html.erb_footer.html.erbのパーシャルには、アプリケーションの多くのページで共有されるコンテンツが含まれている場合があります。特定のページに集中しているときにこれらのセクションの詳細を見る必要はありません。

4.3 partiallocalsオプションなしのrender

上記の例では、renderメソッドは2つのオプション、partiallocalsを取ります。ただし、これらのオプションのみを渡す場合は、これらのオプションを使用せずに済ませることもできます。たとえば、次のように書くこともできます:

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

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

デフォルトでは、ActionView::Partials::PartialRendererは、テンプレートと同じ名前のローカル変数にオブジェクトを持っています。したがって、次のような場合:

<%= render partial: "product" %>

_productパーシャル内では、ローカル変数product@productが格納されます。

objectオプションは、テンプレートのオブジェクトが別の場所にある場合に使用されます(たとえば、別のインスタンス変数やローカル変数にある場合など)。

たとえば、次のような場合:

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

次のようにします:

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

asオプションを使用すると、指定したローカル変数の名前を変更できます。たとえば、productではなくitemにしたい場合は、次のようにします:

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

これは、次のコードと同じです: erb <%= render partial: "product", locals: { item: @item } %>

4.5 コレクションのレンダリング

通常、テンプレートはコレクションを反復処理し、各要素のためにサブテンプレートをレンダリングする必要があります。このパターンは、配列を受け取り、配列の各要素に対して部分テンプレートをレンダリングする単一のメソッドとして実装されています。

したがって、すべての商品をレンダリングするためのこの例:

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

を単一の行で書き直すことができます:

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

コレクションとして部分テンプレートが呼び出される場合、部分テンプレートの個々のインスタンスは、レンダリングされているコレクションのメンバーにアクセスできます。この場合、部分テンプレートは _product であり、その中で product を参照することで、レンダリングされているコレクションのメンバーを取得できます。

コレクションのレンダリングには省略記法も使用できます。@productsProduct インスタンスのコレクションであると仮定すると、次のように書くだけで同じ結果が得られます:

<%= render @products %>

Railsは、コレクション内のモデル名で使用する部分テンプレートの名前を決定します。実際、この省略記法を使用して異なるモデルのインスタンスからなるコレクションをレンダリングすることもでき、Railsはコレクションの各メンバーに適切な部分テンプレートを選択します。

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

メインの部分テンプレートのインスタンス間にレンダリングするためのセカンドパーシャルを指定するには、:spacer_template オプションを使用します:

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

Railsは、各 _product パーシャルの間にデータを渡さずに _product_ruler パーシャルをレンダリングします。

4.7 厳密なローカル変数

デフォルトでは、テンプレートはキーワード引数として任意の locals を受け入れます。テンプレートが受け入れる locals を定義するには、locals マジックコメントを追加します:

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

デフォルト値も指定できます:

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

または、locals を完全に無効にすることもできます:

<%# locals: () %>

5 レイアウト

レイアウトは、Railsコントローラのアクションの結果を囲む共通のビューテンプレートをレンダリングするために使用できます。通常、Railsアプリケーションには、ページがレンダリングされるレイアウトがいくつかあります。たとえば、サイトにはログイン済みユーザー用のレイアウトと、マーケティングやセールスのサイド用の別のレイアウトがあるかもしれません。ログイン済みユーザーレイアウトには、多くのコントローラアクションで表示される必要があるトップレベルのナビゲーションが含まれる場合があります。SaaSアプリのセールスレイアウトには、「価格設定」や「お問い合わせ」ページなどのトップレベルのナビゲーションが含まれる場合があります。各レイアウトには異なる外観と感触があることが期待されます。詳細については、Railsのレイアウトとレンダリングガイドを参照してください。

5.1 部分レイアウト

部分テンプレートには、それに適用される独自のレイアウトを適用することもできます。これらのレイアウトは、コントローラアクションに適用されるレイアウトとは異なりますが、同様の方法で機能します。

たとえば、表示目的のために div で囲まれたページ上に記事を表示しているとします。まず、新しい Article を作成します:

Article.create(body: '部分レイアウトは素晴らしいです!')

show テンプレートでは、box レイアウトで _article 部分テンプレートをレンダリングします:

articles/show.html.erb

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

box レイアウトは、単純に _article 部分テンプレートを div で囲みます:

articles/_box.html.erb

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

部分レイアウトには、render 呼び出しに渡されたローカル変数 article にアクセスできることに注意してください。ただし、アプリケーション全体のレイアウトとは異なり、部分レイアウトにはまだアンダースコアの接頭辞が付いています。

また、yield を呼び出す代わりに、部分レイアウト内でコードブロックをレンダリングすることもできます。たとえば、_article 部分テンプレートがない場合は、次のようにすることもできます:

articles/show.html.erb

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

上記の例と同じ _box 部分テンプレートを使用する場合、同じ出力が生成されます。

6 ビューパス

レスポンスをレンダリングする際、コントローラは異なるビューがどこにあるかを解決する必要があります。デフォルトでは、app/views ディレクトリ内のみを検索します。 prepend_view_pathメソッドとappend_view_pathメソッドを使用して、他の場所を追加し、パスの解決時にそれらに優先順位を付けることができます。

6.1 Prepend View Path

これは、サブドメインのために異なるディレクトリ内にビューを配置したい場合などに便利です。

次のように使用することができます。

prepend_view_path "app/views/#{request.subdomain}"

その後、Action Viewはビューを解決する際にまずこのディレクトリを参照します。

6.2 Append View Path

同様に、パスを追加することもできます。

append_view_path "app/views/direct"

これにより、app/views/directが検索パスの末尾に追加されます。

7 ヘルパー

Railsは、Action Viewで使用するための多くのヘルパーメソッドを提供しています。これには、次のようなメソッドが含まれます。

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

ヘルパーについては、Action View Helpers GuideAction View Form Helpers Guideで詳しく学ぶことができます。

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

Action Viewには、現在のロケールに応じて異なるテンプレートをレンダリングする機能があります。

たとえば、showアクションを持つArticlesControllerがあるとします。デフォルトでは、このアクションを呼び出すとapp/views/articles/show.html.erbがレンダリングされます。しかし、I18n.locale = :deと設定すると、代わりにapp/views/articles/show.de.html.erbがレンダリングされます。ローカライズされたテンプレートが存在しない場合は、非装飾版が使用されます。つまり、すべてのケースにローカライズされたビューを提供する必要はありませんが、利用可能な場合は優先されて使用されます。

同じテクニックを使用して、パブリックディレクトリ内のレスキューファイルをローカライズすることもできます。たとえば、I18n.locale = :deと設定し、public/500.de.htmlpublic/404.de.htmlを作成すると、ローカライズされたレスキューページを使用できます。

RailsはI18n.localeを設定するために使用するシンボルを制限しないため、このシステムを使用して好きな要素に応じて異なるコンテンツを表示することができます。たとえば、いくつかの「エキスパート」ユーザーが「通常」のユーザーとは異なるページを表示する必要がある場合を考えてみましょう。次のようにapp/controllers/application_controller.rbに追加することができます。

before_action :set_expert_locale

def set_expert_locale
  I18n.locale = :expert if current_user.expert?
end

その後、app/views/articles/show.expert.html.erbのような特別なビューを作成することで、エキスパートユーザーにのみ表示されるようにすることができます。

Railsの国際化(I18n)APIについては、こちらを参照してください。

フィードバック

このガイドの品質向上にご協力ください。

タイポや事実の誤りを見つけた場合は、ぜひ貢献してください。 開始するには、ドキュメントへの貢献セクションを読んでください。

不完全なコンテンツや最新でない情報も見つかるかもしれません。 メインのドキュメントに不足しているドキュメントを追加してください。 修正済みかどうかは、まずEdge Guidesを確認してください。 スタイルと規約については、Ruby on Rails Guides Guidelinesを確認してください。

修正すべき点を見つけたが、自分で修正できない場合は、 問題を報告してください

そして最後に、Ruby on Railsのドキュメントに関するあらゆる議論は、公式のRuby on Railsフォーラムで大歓迎です。