AWDwR "Chapter17 Action View" つづきのつづきのつづき

Chapter17つづき、いきますよ。

Layouts and Components

ビューにもDRY原則に則って重複を避けるためのレイアウト、パーシャルズ、コンポーネントという仕組みがある。

まずはレイアウト。レイアウトのテンプレートは以下のような感じ。

<html>
  <body>
    <%= @content_for_layout %>
  </body>
</html>

ミソは@content_for_layoutで、アクションでレンダリングされた結果がセットされ、レイアウトの中でそれが表示される。

レイアウトのテンプレートファイルはコントローラ名がstoreの場合、デフォルトではapp/views/layout/store_layout.[rhtml|rxml]になる。またapplication.[rhtml|rxml]というテンプレートファイルを用意しておくと対応するテンプレートがないコントローラに適用される。

デフォルトのテンプレート以外を使いたい場合はコントローラクラスの中で以下のように指定。

layout "standard"
layout "standard", :except => [:rss, :atom] # 指定されたものには適用しない
layout "standard", :only => [:foo, :bar] # 指定されたものだけに適用する

以下のようにすれば動的にレイアウトを変えることもできるし…

class StoreController < ApplicationController
  layout :determine_layout

  private
  def determine_layout
    (レイアウト名を返す)
  end
end

アクションごとにレイアウトを指定することもできる。

def rss
  render(:layout => false) # レイアウトを使用しない
end

def checkout
  render(:layout => "layouts/simple")
end

また、個々のアクションのテンプレートからレイアウトに対して値を渡すこともできる。

# レイアウト
<html>
  <body>
    <h1><%= title %></h1>
  </body>
</html>

# 個々のアクションのテンプレート
<%= @title="Hello" %> # @titleがレイアウトに渡る 


ページの一部分をテンプレートにしておいて、テンプレート内からそのテンプレートを呼ぶことができる。この一部分のテンプレートのことをパーシャルズ(?)といって、ファイルの名前は_で始める。例えば_article.rhtmlというテンプレートを用意しておくと以下のようにしてテンプレートから呼ぶことができる。

<%= render(:partials => "article", :object => @an_article) %>

一覧表示みたいに繰り返して表示したい場合はパーシャルズを使って

<%= render(:partials => "article", :collection => @article_list) %>

とする。オプションに:spacer_templateというのを指定すると、間にはさむテンプレートを指定できる。


ビューやアクションの中でアクションを呼び出すのをコンポ−ネントというんだけど、コンポーネントはその名のとおりコンポーネント化できる。コンポーネントはcomponentsディレクトリ内にディレクトリを作ってその下にコントローラ、モデル、ビューなどを置いておく。

コンポーネントの呼び出し方は以下のようにディレクトリ付のコントローラを指定する。

<%= render_components(:controller => 'sidebar/link', :action => 'get_link') %>

コンポーネント用コントローラはこの場合sidebarディレクトリ以下に置いておく。

class Sidebar::LinkController < ActionController::Base
  uses_component_template_root
    Link = Struct.new(:name, :url)
    def self.find(*ignored)
      ...
    end
  def get_links
    ...
  end
end

コンポーネント用コントローラが普通のコントローラと違う点は、モジュール内で定義されていること、uses_component_template_rootが宣言されていることの2つ。コンポーネント化しておけば、お友達がそれを気に入った場合そのコンポーネントディレクトリを「はいっ」とあげることができるよ。


もう少し!