Middleman + Foundation + Amazon S3 でのBlogサイト構築(5)テンプレートヘルパの確認

前回はmiddlemanやBlogの設定について記載しました。これで下準備は整ったのでBlogサイトの作成(htmlやcssのコーディング)に入りたいところですが、その前にmiddleman本体やmiddlemanのblog拡張で使える便利なテンプレートヘルパについて確認しておきます。

middleman標準ではlink_toform_tagなどRailsのビューヘルパでお馴染みのもの(と同等のもの)が使えるようになっています。(正確にはこれらのヘルパはPadrinoによってmiddlemanに組み込まれています。)これに加えて、middlemanのblog拡張をインクルードすることで使えるようになるヘルパが多数ありますので、今回はこちらを中心に見ていきたいと思います。

スケルトンに含まれるテンプレートファイル

middleman init my_blog --template=blogで生成されるBlogサイト用のスケルトンに含まれるテンプレートファイルは以下の5ファイルです。

calender.html.erb
feed.xml.builder
index.html.erb
layout.erb
tag.html.erb

拡張子を見れば分かりますが、middelemanのデフォルトのテンプレート言語はERBです。デフォルトで生成されるテンプレートの中に主要なヘルパが含まれているので、1ファイルずつ中身を見ていきたいと思います。

layout.erb

サイト共通のテンプレートファイルで、ファイル名のとおりレイアウトと呼ばれます。<head>要素や、ヘッダ、フッタなど サイト全体で共有するhtmlコンテンツをここに書いていきます。

ポイントとなる部分を見ていきます。

テンプレートファイルの埋め込み(yield)

<div id="main" role="main">
  <%= yield %>
</div>

yieldの部分にはBlogのトップページやBlog記事の本体など、メインとなるhtmlコンテンツが埋め込まれます。これはRailsでもお馴染みの記法です。

例を挙げると、トップページ(インデックスページ)であればindex.html.erbの中身がyeildの部分に埋め込まれて最終的に1つのindex.htmlファイルにコンパイルされます。レイアウトで、メインとなるコンテンツを囲んでいるイメージです。

なお、レイアウトファイル自身はビルド時にlayout.htmlというように個別のhtmlファイルにコンパイルされる必要がないので、拡張子は.erbだけになっています。(index.html.erbなど、最終的にhtmlファイルにコンパイルされるべきものには.htmlを付加します。)

最近投稿されたBlog記事の一覧

<h2>Recent Articles</h2>
<ol>
  <% blog.articles[0...10].each do |article| %>
    <li><%= link_to article.title, article %>
    <span><%= article.date.strftime('%b %e') %></span>
    </li>
  <% end %>
</ol>

最近投稿されたBlog記事の一覧を表示する部分です。 blog.articlesで記事の一覧が取得できます。blog.articles[0...10].each do |article| ... endで、直近の記事×10個を取得して記事1件1件に対してlink_toでリンクを生成しています。

link_toメソッドでは第1引数にリンク名を、第2引数にurlを指定します。article.titleはBlog記事のタイトルを返します。articleはBlog記事のurlに展開されるので、この場合はBlog記事のタイトルをリンク名にしたBlog記事へのリンクが生成されることになります。Blog記事のurlはarticle.urlとも書けますが、link_toにBlog記事を表すオブジェクト(上記のコードではarticle)を渡すと自動的にurlに展開してくれます。

article.date.strftime('%b %e')はBlog記事の投稿日です。

タグごとのBlog記事数

<h2>Tags</h2>
  <ol>
    <% blog.tags.each do |tag, articles| %>
      <li><%= link_to tag, tag_path(tag) %> (<%= articles.size %>)</a></li>
    <% end %>
  </ol>

タグの一覧と、タグごとのBlog記事数を表示する部分です。blog.tagsでタグとそのタグが設定されているBlog記事をハッシュ形式で取り出せます(タグがキーで、Blog記事の配列が値です)。tag_pathは引数にタグを渡すとタグページ(該当のタグが設定されている記事の一覧ページ)へのurlを生成してくれます。 articles.sizeは該当のタグが設定されているBlog記事数を返します。

年ごとのBlog記事数

<h2>By Year</h2>
  <ol>
    <% blog.articles.group_by {|a| a.date.year }.each do |year, articles| %>
      <li><%= link_to year, blog_year_path(year) %> (<%= articles.size %>)</a></li>
    <% end %>
  </ol>

年ごとのBlog記事数を表示する部分です。タグの一覧ページとほぼ同様の内容です。blog.articles.group_by {|a| a.date.year }で年ごとのBlog記事をハッシュ形式で取り出せます(年がキーで、Blog記事の配列が値です)。tag_pathは引数に年を渡すとカレンダページ(年ごとのBlog記事の一覧ページ)へのurlを生成してくれます。

index.html.erb

サイトのトップページ用のテンプレートです。レイアウトと異なり、前述のとおりこちらはhtmlファイルにコンパイルされる必要があるので拡張子は.html.erbとなっています。

ページ固有の設定

---
pageable: true
per_page: 10
---

冒頭にある---で囲まれた部分はForntmatterと呼ばれるもので、 YAMLまたはJSONでページ固有の変数を設定できます。

デフォルトではYAMLで、ページネーションに関する変数が設定されています。 前回config.rbblog.paginate = trueを設定してページネーションを有効化しましたが、ページネーションを使うには個々のページでもpageable: trueを設定する必要があります。per_pageは1ページあたりの表示項目数です。こちらはconfig.rbの設定がデフォルト値として扱われるので、個々のページで設定する必要はありません。デフォルト設定を上書きしたい場合はページごとにForntmatterで設定します。

ページネーション(前ページへのリンク)

<% if paginate && num_pages > 1 %>
  <p>Page <%= page_number %> of <%= num_pages %></p>

  <% if prev_page %>
    <p><%= link_to 'Previous page', prev_page %></p>
  <% end %>
<% end %>

ページネーションでの、前ページ(Previous page)へのリンクを表示する部分です。 ページネーションが有効かつページ数が1より多い場合にリンクを表示しています。

num_pagesは総ページ数、page_numberは現在のページのページ番号です。 prev_pageは前ページを表すオブジェクトなので、link_toに渡すと前ページへのリンクが生成されます。

Blog記事の一覧

<% page_articles.each_with_index do |article, i| %>
  <h2><%= link_to article.title, article %>
  <span><%= article.date.strftime('%b %e') %></span></h2>
  <!-- use article.summary(250) if you have Nokogiri available to show just
       the first 250 characters -->
  <%= article.body %>
<% end %>

page_articlesは現在のページに含まれるBlog記事の配列を返します。記事へのリンクを生成する部分のコードは、Recent Articlesと同一です。

article.bodyはBlog記事の本文を返します。またデフォルトではコメントアウトされていますが、article.summaryと書くとBlog記事の要約(Blog本文から一部分を切り出したもの)を返します。デフォルトでは記事本文の先頭から250文字までが切り出されます。

config.rbblog.summary_length = <文字数>と書くと要約として切り出す文字数を変更できます。 nokogiriをインストールしておくと、article.summary(250)という風にテンプレート側で切り出す文字数を指定することもできます。

ページネーション(次ページへのリンク)

<% if paginate %>
  <% if next_page %>
    <p><%= link_to 'Next page', next_page %></p>
  <% end %>
<% end %>

最後はページネーションでの、次ページ(Next page)のリンクを表示する部分です。

calender.html.erb, tag.html.erb

calender.html.erbは年 or 月 or 日ごとの、tag.html.erbはタグごとのBlog記事のタイトル一覧(記事へのリンク)を表示するためのテンプレートです。中身はindex.html.erbとほぼ同じなので説明は省略します。

feed.xml.builder

RSS/ATOMフィードを生成するためのテンプレートです。フィードの生成にはbuilderが使用されています。(Blogサイトのスケルトン生成時に自動でbuilderのgemがインクルード(Gemfileに追加)されます。) 最低限、site_url, xml.title, xml.subtitle, xml.authorをサイトに合わせて修正しておけばフィードが生成されます。フィードには<BlogサイトのURL>/feed.xmlでアクセスできます。本サイトであればhttp://nmbr8.com/feed.xmlでアクセスできます。

xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do
  site_url = "http://nmbr8.com/" # サイトに合わせて修正
  xml.title "はちびる日記" # サイトに合わせて修正
  xml.subtitle "日々の作業メモやランニングの記録など" # サイトに合わせて修正
  xml.id URI.join(site_url, blog.options.prefix.to_s)
  xml.link "href" => URI.join(site_url, blog.options.prefix.to_s)
  xml.link "href" => URI.join(site_url, current_page.path), "rel" => "self"
  xml.updated(blog.articles.first.date.to_time.iso8601) unless blog.articles.empty?
  xml.author { xml.name "Blog Author" }

  blog.articles[0..5].each do |article|
    xml.entry do
      xml.title article.title
      xml.link "rel" => "alternate", "href" => URI.join(site_url, article.url)
      xml.id URI.join(site_url, article.url)
      xml.published article.date.to_time.iso8601
      xml.updated File.mtime(article.source_file).iso8601
      xml.author { xml.name "Article Author" }
      # xml.summary article.summary, "type" => "html"
      xml.content article.body, "type" => "html"
    end
  end
end

まとめ

Blog用のテンプレートヘルパを使うと、タグや最近の投稿などの基本的な機能については容易にサイトに組み込むことができます。本サイトもこれらのヘルパを含むロジックについてはスケルトンで生成されたものをほぼそのまま使っています。

次はようやくBlogサイトの作成(htmlやcssのコーディング)に入ります。デフォルトのスケルトンの状態ではデザイン的に寂しいので(というかデザインがゼロの状態なので)、今回見たテンプレートヘルパを活かしつつ、Foundationを使ってサイトのデザインを作りこんでいきます。

middleman  aws  s3 
comments powered by Disqus