Railsで静的ページの管理を簡単にするgemを作った

はじめに

先月、エラーページをAsset Pipelineで管理する - WEB SALADというエントリを書いたのですが、あの後「これはエラーページに限らずもっと一般化できるのでは」と思ってgemを作ってみました。

このエントリでは、このgemの紹介と使い方を説明したいと思います。

Gakubuchiとは

READMEにも書いてあるように、GakubuchiはRailsアプリケーションにおける静的ページをAsset Pipelineで管理するためのgemです。
その仕組みは前回のエントリでも述べた通りで、次のようになっています。

  1. 使用するテンプレートエンジンを登録する
  2. app/assets/templatesのようなディレクトリを作り、そこに静的ページを書く
  3. assets:precompileをフックして、実行後にコンパイルされた静的ページをpublic配下に移す

1の設定作業や3のフックなどはgem側でよしなにやってくれるので、開発者は静的ページの実装に集中することができます。

使い方

以下では、Gakubuchiを使ってRailsの404ページを再現するというタスクを通じて、その使い方を説明していきたいと思います。

インストール

まず、Gemfileに次の記述を追加してbundle installします。
今回はテンプレートエンジンにSlimを使うので、slim-railsも併せて追加しておきます。

gem 'gakubuchi'
gem 'slim-rails'

次に、インストールのためのジェネレーターコマンドを実行します。

rails generate gakubuchi:install

実行すると、以下の2つが生成されます。

  • 設定ファイル: config/initializers/gakubuchi.rb
  • 静的ページを配置するディレクトリ: app/assets/templates

静的ページの実装

まず、app/assets/templates/404.html.slimを次のように実装します。

doctype html
html
  head
    title The page you were looking for doesn't exist (404)
    meta name='viewport' content='width=device-width,initial-scale=1'
    = stylesheet_link_tag 'error', media: 'all'
  body
    .dialog
      div
        h1 The page you were looking for doesn't exist.
        p You may have mistyped the address or the page may have moved.
      p If you are the application owner check the logs for more information.

静的ページでは、stylesheet_link_tagを始めとするヘルパーメソッドを使うことができます。
例えば、以下のようなものがあります。

  • asset_path
  • content_tag
  • favicon_link_tag
  • image_tag
  • javascript_include_tag

利用可能な全てのメソッドを知りたい場合には、以下のコードをコンソールで実行してください。

Sprockets::Rails::Helper.instance_methods

次に、app/assets/stylesheets/error.scssを用意します。
こちらは、元のものをSCSSを使って書き換えただけです。

body {
  background-color: #EFEFEF;
  color: #2E2F30;
  text-align: center;
  font-family: arial, sans-serif;
  margin: 0;
}

div.dialog {
  width: 95%;
  max-width: 33em;
  margin: 4em auto 0;

  & > div {
    border: 1px solid #CCC;
    border-right-color: #999;
    border-left-color: #999;
    border-bottom-color: #BBB;
    border-top: #B00100 solid 4px;
    border-top-left-radius: 9px;
    border-top-right-radius: 9px;
    background-color: white;
    padding: 7px 12% 0;
    box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
  }

  & > p {
    margin: 0 0 1em;
    padding: 1em;
    background-color: #F7F7F7;
    border: 1px solid #CCC;
    border-right-color: #999;
    border-left-color: #999;
    border-bottom-color: #999;
    border-bottom-left-radius: 4px;
    border-bottom-right-radius: 4px;
    border-top-color: #DADADA;
    color: #666;
    box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
  }
}

h1 {
  font-size: 100%;
  color: #730E15;
  line-height: 1.5em;
}

このスタイルシートがprecompileの対象になるように、config/initializers/assets.rbに次の記述を追加します。

Rails.application.config.assets.precompile += %w(error.css)

ここで一度、エラーページの表示を確認してみましょう。
サーバーを立ち上げてhttp://localhost:3000/assets/404.htmlにアクセスします。

f:id:Yasaichi:20150817000552p:plain

どう見てもあのエラーページです。

Precompile

最後に、作成したエラーページを含むassetをコンパイルします。

rake assets:precompile

実行後のpublic/404.htmlは次のようになりました。

<!DOCTYPE html>
<html>
  <head>
    <title>The page you were looking for doesn't exist (404)</title>
    <meta content="width=device-width,initial-scale=1" name="viewport" />
    <link rel="stylesheet" media="all" href="/assets/error-5671085db2fed6c482b9f8be62a4960fc15e7e3175169d3502abe723064793d4.css" />
  </head>
  <body>
    <div class="dialog">
      <div>
        <h1>
          The page you were looking for doesn't exist.
        </h1>
        <p>
          You may have mistyped the address or the page may have moved.
        </p>
      </div>
      <p>
        If you are the application owner check the logs for more information.
      </p>
    </div>
  </body>
</html>

いい感じですね!

課題

静的ページ内で使用されているassetのうち、デフォルトではAsset Pipelineの対象にならないものを自動追加できるようにしようと思ったのですが、茨の道が見えたので諦めました。
いいアイデアがあれば、プルリクエストお願いします\(^o^)/

おわりに

前回のエントリ、我ながら「これは結構いい線いってるのでは?」と思って書いたのに全然バズらなくて(笑)、悔しくてgemを作ったというのが本当の理由だったりする。