🎉

[Rails]slim

に公開

slimとは?

slimはRubyで使うテンプレートエンジンの一つで、htmlファイルをより簡潔でスマートに記述することができます。
書き方の特徴として

  • <>がいらない
  • <%= %> →  =
  • <% %> → -
  • コメント → /
  • id指定 → #
  • class指定 → .
    のような違いがあります。
テンプレートエンジンとは?

テンプレートと呼ばれる通常のhtmlで書いたコードと変数などプログラミングによって書かれたコードを合成してビューファイルを作り出すものです。
Railsでは.erb``.slim``.hamlがあります。

slimを導入

Railsではデフォルトのテンプレートエンジンはerbなので、slimを使うためにgemをインストールします。

Gemfile
gem 'slim-rails'

記述できたらbundle installを忘れずに
これでindex.html.slimのように拡張子の.slimをviewファイルに使えるようになりました!
ちなみに同じ名前のerbファイルとslimファイルがある場合、erbファイルが優先して読み込まれるので削除するなど注意が必要です。

既存のerbファイルをslimファイルに変更

既存のerbファイルをすべて書き直すのは面倒だなと思っていたのですが、gemを使うことで自動で変換してくれるみたいです。
同じようにGemfileに記述してbundle installします。

Gemfile
gem 'html2slim'

変換するためにターミナルで下記のコードを実行します。

ターミナル
# erbファイルを残して変換
erb2slim 変換するファイルがあるフォルダまたはファイル名

# erbを削除して変換
erb2slim 変換するファイルがあるフォルダまたはファイル名 -d

今回は作成済みのmeshiterroという投稿サイトをslimに変更してみました。
viewファイルまとめて変更したので下記のように記述して実行しました。

ターミナル
erb2slim app/views -d


こんな感じでファイルが置き換わっていました。
内容は下記のように変更されています。(ファイルを1つピックアップしました。)

views/post_images/show.html.erb
<div>
    <%= image_tag @post_image.get_image(100, 100) %>
    <p>ショップ名: <%= @post_image.shop_name %></p>
    <p>説明: <%= @post_image.caption %></p>
    <p>投稿ユーザー画像: <%= image_tag @post_image.user.get_profile_image(100,100) %></p>
    <p>ユーザーネーム: <%= @post_image.user.name %></p>
    <p>投稿日時: <%= @post_image.created_at.strftime('%Y/%m/%d') %></p>
    
    <% if @post_image.user == current_user %>
     <%= link_to "削除", post_image_path(@post_image), method: :delete %>
    <% end %>
    
    <span id="favorite_buttons_<%= @post_image.id %>">
      <%= render "favorites/favorite", post_image: @post_image %>
    </span>
    
</div>

<div>
    <p>コメント件数: <%= @post_image.post_comments.count %></p>
    <% @post_image.post_comments.each do |post_comment| %>
    <p><%= image_tag post_comment.user.get_profile_image(100,100) %></p>
     <%= post_comment.user.name %>
     <%= post_comment.created_at.strftime('%Y/%m/%d') %><%= post_comment.comment %>
     <% if post_comment.user == current_user %>
      <%= link_to "削除", post_image_post_comment_path(post_comment.post_image, post_comment), method: :delete %>
     <% end %>
    <% end %>
</div>

<div>
    <%= form_with model: [@post_image, @post_comment] do |f| %>
    <%= f.text_area :comment, rows: '5', placeholder: "コメントをここに" %>
    <%= f.submit "送信する" %>
    <% end %>
</div>
views/post_images/show.html.slim
div
  = image_tag @post_image.get_image(100, 100)
  p
    | ショップ名: 
    = @post_image.shop_name
  p
    | 説明: 
    = @post_image.caption
  p
    | 投稿ユーザー画像: 
    = image_tag @post_image.user.get_profile_image(100,100)
  p
    | ユーザーネーム: 
    = @post_image.user.name
  p
    | 投稿日時: 
    = @post_image.created_at.strftime('%Y/%m/%d')
  - if @post_image.user == current_user
    = link_to "削除", post_image_path(@post_image), method: :delete
  |  <span id="favorite_buttons_
  = @post_image.id
  | "> 
  = render "favorites/favorite", post_image: @post_image
div
  p
    | コメント件数: 
    = @post_image.post_comments.count
  - @post_image.post_comments.each do |post_comment|
    p
      = image_tag post_comment.user.get_profile_image(100,100)
    = post_comment.user.name
    = post_comment.created_at.strftime('%Y/%m/%d')
    = post_comment.comment
    - if post_comment.user == current_user
      = link_to "削除", post_image_post_comment_path(post_comment.post_image, post_comment), method: :delete
div
  = form_with model: [@post_image, @post_comment] do |f|
    = f.text_area :comment, rows: '5', placeholder: "コメントをここに"
    = f.submit "送信する"

様々な要素が変わっていました。
これから基本的な書き方や文法を説明します。

基本文法

各タグの書き方

slimには、<>がいらないという特徴があります!
これだけで一気に記述量と見た目が変わります。
比較するとこのようになります。

slim
div
  h1 title
  ul
    li Ruby
    li Rails
    li HTML
erb
<div>
  <h1>title</h1>
  <ul>
    <li>Ruby</li>
    <li>Rails</li>
    <li>HTML</li>
  </ul>
</div>

テキストの書き方

テキスト|で定義します。

slim
p
  | slim  
  
:

p
  |  slimはviewファイルをわかりやすく
     また簡潔に記述できます。
erb
<p>erb</p>

:

<p>slimはviewファイルをわかりやすく
    また簡潔に記述できます。</p>

2文は改行なしで表示されます。改行させたい場合はerbと同じように<br>を使えば改行できます。

クラスやidの指定

クラスやidはそれぞれ、., #で表現することができます。

slim
div.content
  p.title タイトル
  
div#content
  p#title タイトル
  
div.content#article
  p.title.text-center タイトル
erb
<div class="content">
  <p class="title">タイトル</p>
</div>

<div id="content">
  <p id="title">タイトル</p>
</div>

<div class="content" id="article">
  <p class="title text-center">タイトル</p>
</div>

クラスとidを連続して使用すると記述量が段違いになります。

条件式などの書き方

slimでif文を書くときは、-で囲って上げる必要があります。
<% >は-で
<%= >は=を使います。

(例)if文

slim
- if current_user.nil?
  li 新規登録
- else
  li ログイン
erb
<% if current_user.nil? %>
  <li>新規登録</li>
<% else %>
  <li>ログイン</li>
<% end %>

(例)each文
前提として、@post_image = PostImage.allとします。

slim
- @post_images.each do |post_image|
  p
      | 説明: 
      = post_image.caption
    p
      |  投稿者:
      = post_image.user.name
erb
<% @post_images.each do |post_image| %>
  <p>
    説明:
    <%= post_image.caption %>
  </p>
   <p>
    投稿者:
    <%= post_image.user.name %>
  </p>  
<% end %>

(例)link_toメソッド

slim
= link_to "投稿一覧へ", post_images_path
erb
<%= link_to "投稿一覧へ", post_images_path %>

bootstrapのtable

bootstrapが適用されている場合でも基本的な書き方は同じです。
tableの書式設定は.でつなげるところを気を気を付ければ大丈夫そうです。

slim
table.table.table-border-less
  thead
    tr
      th."col-4" 名前
      th."col-4" 会員id
      th."col-4" 説明
  tbody
    @posts.each do |post|
      tr
        td."col-4" post.name
        td."col-4" post.user_id
        td."col-4" post.introduct
erb
<table class="table table-borderless>
  <thead>
    <tr>
      <th class="col-4">名前</th>
      <th class="col-4">会員id</th>
      <th class="col-4">説明</th>
    </tr>
  </thead>
  <tbody>
    <% @posts.each do |post| %>
      <tr>
        <td class="col-4">post.name</td>
        <td class="col-4">post.user_id</td>
        <td class="col-4">post.introduct</td>
      </tr>
    <% end %>
  </tbody>
</table>

参考にさせていただいた記事

https://qiita.com/ngron/items/c03e68642c2ab77e7283
https://qiita.com/yoshinyan/items/f709a29def71da798250

まとめ

特に現場ではslimというフォーマットで書く所が多い様なので、書き方に慣れておく必要があります。
当初、想像していたよりも簡単で複雑じゃないなという印象がありました!
ただ、今の段階だと3か月間書きなれてきたコードと違う箇所が多いので違和感だらけですが、慣れると病みつきというコメントを見つけたので楽しみに使っていきたいと思います。

Discussion