読者です 読者をやめる 読者になる 読者になる

Rails Webook

自社のECを開発している会社で働いています。Rails情報やサービスを成長させる方法を書いていきます

早い、簡単、生産的!? RailsのHTMLテンプレートエンジン Slim入門

Rails View Rails gem

はじめに

RailsではView(HTML出力)のためには標準ではERB(.erb)を使用しています。
しかし、erbは汎用的なテンプレートエンジンであり、HTML以外にも様々なファイルにRubyコードを
埋め込めることができるため、HTMLを作成するにおいていくらか冗長な箇所があります。

そのため、より生産的にHTMLを作成するために、Railsでは

という2つのHTML用のテンプレートエンジンがよく使われます。


そして、今回はタイトルからも分かるようにSlimについて説明します。

Hamlについては、こちらを参照して下さい。

Slimの特徴としては、

  • タブによりHTMLのタグ構造を表すので、必要最低限のコードだけで良いのでコーディング時間が減る
  • デフォルトでHTMLエスケープをするので安全
  • erbに比べて、スピードが速い

※ほぼHamlと同じです。

動作確認

目次

  1. Slimの基礎
  2. RailsにSlimの導入
  3. erbをslimに書き換えていく
  4. おまけ:Slimのリファレンスシート
  5. おまけ:HTMLやerbをSlimに変換するツール: html2slim


1. Slimの基礎

Slimはシンプルな記法で難しくはないので、実際にerbとslimのソースコードを比べて、1つ1つ説明していきます。
Slimの拡張子は、.slimにする必要があります。

# app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
  <title>SlimTest</title>
  <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true %>
  <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
  <%= csrf_meta_tags %>
</head>
<body>

<header id="header">
  <h1 class="title logo">Slim Test</h1>
</header>

<%= yield %>

</body>
</html>
# app/views/layouts/application.html.slim
DOCTYPE
html
  head
    title SlimTest
    = stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track' => true
    = javascript_include_tag 'application', 'data-turbolinks-track' => true
    = csrf_meta_tags

  body

    header#header
      h1.title.logo Slim Test

    == yield

Slimの簡単な覚え方

上記のerbとslimを見比べながら、下記のルールを見て下さい。

  1. <、>、<%、%>などのタグを削除する。閉じタグは全て削除する。
  2. each、ifなどのロジック部分の先頭に-を記載する。(endは必要ない)
  3. <%= ... >=にする。yieldrenderのときは、==にする。
  4. class属性やid属性は、p.fieldsp#contentsなどにする。タグがdivのときはdivを省略し#contentと記載する。
  5. コメントは、/ このコメントはHTMLに変換後に表示されない/! このコメントはHTMLに変換後にコメントになるで記載する。


2. RailsにSlimの導入

Railsプロジェクトの作成

まず、いつも通りRailsプロジェクトを作成します。

$ rails new slim_test

次に、商品(Product)のソース一式をScaffoldを使って作成します。

$ cd slim_test
$ rails g scaffold Product name:string description:text price:integer discontinued:boolean

DBマイグレートをします。

$ rake db:migrate

これで、商品(Product)の一覧表示、作成、更新、削除ができました。
$ rails serverでローカルのサーバを起動していくつかデータを入力してみました。

f:id:nipe880324:20140929214513p:plain:w480

SlimをRailsに導入

では、実際にRailsにSlimを導入していきましょう。
Gemfileに下記を追加します。

gem 'slim-rails'

その後、Slimをインストールします。

$ bundle install

これで、RailsにSlimが導入されたので、以降はxxx.html.slimという拡張子でファイルを作成することでSlimとしてRailsが読み込んでくれます。

ERBSlimで同名のファイルがある場合は、ERBが読み込まれるので、ERBファイルは削除して下さい。例えば、index.html.erbindex.html.slimがある場合、index.html.erbが読み込まれてしまうため、削除して下さい。

slim-rails gem をインストール後に、rails generaterでscaffoldやcontrollerを作成すると、ビューファイルは全て.erbの代わりに.slimで作成されます。



2. erbをslimに書き換えていく

では、Scaffoldで作成した.erbを1画面ずつ.slimに変更していきます。
変更後のSlimファイルを見る前に、自分で上記の「1. Slimの基礎」を確認しながら手を動かしながらSlimファイルを作成することにより、Slimの書き方に慣れるのでおすすめです。

一覧画面

まずは、一覧画面を変更します。
index.html.erbは次のようになっています。

# app/views/products/index.html.erb
<h1>Listing products</h1>

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Description</th>
      <th>Price</th>
      <th>Discontinued</th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @products.each do |product| %>
      <tr>
        <td><%= product.name %></td>
        <td><%= product.description %></td>
        <td><%= product.price %></td>
        <td><%= product.discontinued %></td>
        <td><%= link_to 'Show', product %></td>
        <td><%= link_to 'Edit', edit_product_path(product) %></td>
        <td><%= link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' } %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<br>

<%= link_to 'New Product', new_product_path %>


index.html.slimを新しく作成し、これを1つ1つ直していきましょう。

下記が変換後の一覧画面です。
基本は、<と>を削除し、eachなどのロジック部分は-をつける、閉じタグは削除です。

# app/views/products/index.html.slim
h1 Listing products

table
  thead
    tr
      th Name
      th Description
      th Price<
      th Discontinued
      th colspan="3"

  tbody
    - @products.each do |product|
      tr
        td = product.name
        td = product.description
        td = product.price
        td = product.discontinued
        td = link_to 'Show', product
        td = link_to 'Edit', edit_product_path(product)
        td = link_to 'Destroy', product, method: :delete, data: { confirm: 'Are you sure?' }

br

= link_to 'New Product', new_product_path

.erbファイルが存在するとそちらが表示されてしまうので、ファイル名を変更するか削除してから、
サーバーを再起動しなおして、一覧画面を確認してみましょう。
表示は変わっていませんね。

f:id:nipe880324:20140929214513p:plain:w480

新規/編集画面

次は、新規、編集画面です。

# app/views/products/new.html.erb
<h1>New product</h1>

<%= render 'form' %>

<%= link_to 'Back', products_path %>
# app/views/products/edit.html.erb
<h1>Editing product</h1>

<%= render 'form' %>

<%= link_to 'Show', @product %> |
<%= link_to 'Back', products_path %>
# app/views/products/_form.html.erb
<%= form_for(@product) do |f| %>
  <% if @product.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(@product.errors.count, "error") %> prohibited this product from being saved:</h2>

      <ul>
      <% @product.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="field">
    <%= f.label :name %><br>
    <%= f.text_field :name %>
  </div>
  <div class="field">
    <%= f.label :description %><br>
    <%= f.text_area :description %>
  </div>
  <div class="field">
    <%= f.label :price %><br>
    <%= f.number_field :price %>
  </div>
  <div class="field">
    <%= f.label :discontinued %><br>
    <%= f.check_box :discontinued %>
  </div>
  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>


ではSlimに変換します。
renderyeildは、=ではなく、==です。
また、文字列(今回は|)を表示するには、'が必要です。

# app/views/products/new.html.slim
h1 New product

== render 'form'

= link_to 'Back', products_path
# app/views/products/edit.html.slim
h1 Editing product

== render 'form'

= link_to 'Show', @product
'|
= link_to 'Back', products_path
# app/views/products/_form.html.slim
= form_for(@product) do |f|
  - if @product.errors.any?
    #error_explanation
      h2 = "#{pluralize(@product.errors.count, "error")} prohibited this product from being saved:"

      ul
        - @product.errors.full_messages.each do |message|
          li = message

  .field
    = f.label :name
    br
    = f.text_field :name
  .field
    = f.label :description
    br
    = f.text_area :description
  .field
    = f.label :price
    br
    = f.number_field :price
  .field
    = f.label :discontinued
    br
    = f.check_box :discontinued
  .actions
    = f.submit

では、新規画面を開いてみましょう。
上手く行っていますね。順調です。

f:id:nipe880324:20140929220337p:plain:w480

詳細画面

では、この調子で詳細画面を変換していきましょう。
ほぼほぼ慣れてきたと思います。

# app/views/products/show.html.erb
<p id="notice"><%= notice %></p>

<p>
  <strong>Name:</strong>
  <%= @product.name %>
</p>

<p>
  <strong>Description:</strong>
  <%= @product.description %>
</p>

<p>
  <strong>Price:</strong>
  <%= @product.price %>
</p>

<p>
  <strong>Discontinued:</strong>
  <%= @product.discontinued %>
</p>

<%= link_to 'Edit', edit_product_path(@product) %> |
<%= link_to 'Back', products_path %>


Slimへの変換のポイント

  • id属性は#、class属性は.で始めることがコツです
  • #.の前にタグ名を記載しない場合(例: .disable)は、div要素として変換されます。
  • 複数のクラスを記載したい場合は、.でつなげる(例:input.btn.btn-default.btn-sm
# app/views/products/show.html.haml
p#notice = notice

p
  strong Name:
  = @product.name

p
  strong Description:
  = @product.description

p
  strong Price:
  = @product.price

p
  strong Discontinued:
  = @product.discontinued

= link_to 'Edit', edit_product_path(@product)
'|
= link_to 'Back', products_path

では、詳細画面を見てみましょう。
これで、一通りの画面をSlimにすることができました :)

f:id:nipe880324:20140929220852p:plain:w480


4. おまけ:Slimのリファレンスシート

Slimの変換ルールで困った場合は次のURLを参照して下さい。
http://www.e2esound.com/wp/2013/07/22/21_tips_to_use_slim_for_markup_engineer/#sec16



5. おまけ:HTMLやerbをSlimに変換するツール: html2slim

また、既にerbで多くのViewファイルを作成してしまっている場合は、erbをslimに変換するhtml2slimというツールがあります。
html2slimの使い方

ちなみに、ツールは万能ではなく、上手くSlimに変換できてない箇所がある可能性もあるので、全ての画面に対してレイアウト崩れのチェックはしてください。

参考文献

以上です。
よく分からない箇所や誤りなどがありましたら、コメントの記入をお願いします。