Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Haml で閉じタグに悪戦苦闘してRails を学んだお話

Rails を使い始めてからたまにテンプレートでHaml を使う機会があるのですが、先日下記HTML のようなものを書きたいと思いました。

<div class="hoge">
  <div class="fuga">item1</div>
  <div class="fuga">item2</div>
</div>
<div class="hoge">
  <div class="fuga">item3</div>
  <div class="fuga">item4</div>
</div>

まずはERB に起こしてみました。

<% items.each_with_index do |item, index| %>
  <% if index % 2 == 0 %>
    <div class="hoge">
  <% end %>
  <div class="fuga"><%= item.to_s %></div>
  <% if index % 2 == 1 %>
    </div>
  <% end %>
<% end %>
<%# 凄い雑です、奇数で終わる場合とか無視です %>

しかしこれをHaml で書こうとすると途端に面倒なことになります。何しろインデントが命のHaml です。

- items.each_with_index do |item, index|
  - if index % 2 == 0
    .hoge
  # ...どうすればいいのん?(´・ω・`)

Haml を使ったことがある方はわかると思いますが、閉じタグが自動で入れられてしまいます。上記のif 文を閉じる時には同時に<div class="hoge"> も閉じられてしまいます。

ひとまず力技でやってみる

Haml で書けないならRails で書けばいいじゃない。ということでやってみました。

- items.each do |item|
  - if index % 2 == 0
    = "<div class='hoge'>".html_safe
  .fuga= item.to_s
  - if index % 2 == 1
    = "</div>".html_safe

動いたには動いたけど、格好悪い。

surround を発見し、使ってみた

調べてみたところ、HAML にsurround というメソッドがありました。これはこのメソッドのブロックの前後に任意の文字列を入れることが可能です。

- items.each_with_index do |item, index|
  = surround(index % 2 == 0 ? "<div class='hoge'>".html_safe : "", index % 2 == 1 ? "</div>".html_safe : "") do
    .fuga= item.to_s

出来た!しかも短い!でも大バカヤローでした。

いつからそのERB が最適だと錯覚していた?

社内で上記の話をしてみたところ、each_slice があるじゃないかと突っ込みをくらいました。ERB にすると下記の通りです。

<% items.each_slice(2) do |temp_items| %>
  <div class="hoge">
    <% temp_items.each do |item| %>
      <div class="fuga"><%= item.to_s %></div>
    <% end %>
  </div>
<% end %>

おぉ、これならHaml にも簡単に直せる!

- items.each_slice(2) do |temp_items|
  .hoge
    - temp_items.each do |item|
      .fuga= item.to_s

今度こそ出来た!しかもさっきより読みやすい!きっとこっちの方が良い解決案だと思います。

でもこれより更に良い解決方法はあるかもしれません、知ってる方はコメントください。

関連記事

Railsでnil? blank? empty? present?を使いこなそう

Rubyにおけるunlessとコードの読みやすさについて

Railsでbefore_filter/before_actionがアクションを中止する仕組みを読んでみる


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。