【Rails】Slimで入れ子になっている要素の親タグのみを分岐させる

Slimで、入れ子になっている子タグはそのままで、親タグのみ切り替えたいケースの書き方でハマったのでメモ。

具体的にはこんな感じのHTMLを出力したいときです。

```html:求めるHTML

<div class="User__list">

  <!-- 選択中ユーザの場合、親タグをaタグではなくdivタグにしたい -->
  <div class="User__listSection--selected">
    <div>[ユーザ名]</div>
    <div>[メールアドレス]</div>
  </div>

  <a class="User__listSection"> <!-- hrefは割愛 -->
    <div>[ユーザ名]</div>
    <div>[メールアドレス]</div>
  </a>

  <a class="User__listSection">
    <div>[ユーザ名]</div>
    <div>[メールアドレス]</div>
  </a>

  ...

</div>
```

## ダメな例
直感的にはこう書きたいところですが、slimには `end` が無いのでこれだとエラーになってしまいます。

```slim:slim
.User__list
  - users.each do |user|
    - if current_user == user
      .User__listSection--selected
    - else
      a.User__listSection
    - end / slimに end は無いのでエラー！
        div #{user.name}
        div #{user.email}
```

## 実現できるけど微妙な例
一番素朴にやるとこうなると思います。

```slim:slim
.User__list
  - users.each do |user|
    - if current_user == user
      / 選択中ユーザの場合、親タグをaタグではなくdivタグにする
      .User__listSection--selected
        div #{user.name}
        div #{user.email}
    - else
      a.User__listSection
        div #{user.name}
        div #{user.email}
```

これは入れ子のタグを2回書いていて冗長なのであまり好ましくないですね。メンテナンス性も極めて悪いです。

## 動的タグを使ってちょっぴりスマートに書いた例

[動的タグ](https://github.com/slim-template/slim/blob/master/README.jp.md#%E5%8B%95%E7%9A%84%E3%82%BF%E3%82%B0-)を使うと入れ子のタグは一度だけ書けば済むようになります。

```slim:slim
ruby:
  def user_list_section_tag(current_user, user)
    if current_user == user
      # 選択中ユーザの場合、親タグをaタグではなくdivタグにする
      { tag: 'div', class: 'User__listSection--selected' }
    else
      { tag: 'a', class: 'User__listSection' }
    end
  end

.User__list
  - users.each do |user|
    *user_list_section_tag(current_user, user)
      div #{user.name}
      div #{user.email}
```

複雑な分岐がある場合は動的タグを使うと良さそうですが、slimの中に急にrubyが出てくるのはちょっと気持ち悪い気がします。

## content_tagを使って書いた例

[content_tag](https://apidock.com/rails/ActionView/Helpers/TagHelper/content_tag)でタグを生成するようにすれば、slim内にrubyを書かずに済みます。

```slim:slim
.User__list
  - users.each do |user|
    - user_list_section_attrs = current_user == user \
      ? { class: "User__listSection--selected" } \
      : { class: "User__listSection" }

    / 選択中ユーザの場合、親タグをaタグではなくdivタグにする
    = content_tag(current_user == user ? :div : :a, '', user_list_section_attrs)
      div #{user.name}
      div #{user.email}
```

`content_tag` を使えば確かにRubyを書かずに済みますが、`current_user == user` が2回出てきたりして、むしろこっちの方が分かりづらいのでは？という気もします。
が、純粋にslimだけで書けるのでこちらの方が僕は良いと感じています。

もっとスマートな方法があればどなたか教えて欲しいです！ :bow: 

## 追記：tagを使ってもっとスマートに書いた例

@eRy-sk さんに [コメント](https://qiita.com/mishiwata1015/items/407e924263d698ddeaae#comment-ae3fe766933c6d013f0f) でより良い書き方を教えていただきました！ありがとうございます！ 

[tag](https://apidock.com/rails/ActionView/Helpers/TagHelper/tag) に `send` で生成したいタグ名を分岐して渡します。

```slim:slim
.User__list
  - users.each do |user|
    - selected = current_user == user

    / 選択中ユーザの場合、親タグをaタグではなくdivタグにする
    = tag.send(selected ? 'div' : 'a', class: "User__listSection#{'--selected' if selected}")
      div = user.name
      div = user.email
```

`content_tag` だと第二引数が悲しいことになりますし、この `tag` を使う書き方が良さそうですね！


## さらに追記： content_tagでもっとスマートに書いた例

@scivola  さんに [コメント](https://qiita.com/mishiwata1015/items/407e924263d698ddeaae#comment-9a670ed2fa8800133660) でもっとスマートな書き方を教えていただきました！ありがとうございます！！！

`content_tag` に渡す引数として、タグ名も含めた配列を分岐して定義しておいて、それを渡すようにします。

```slim:slim
.User__list
  - users.each do |user|
    / 選択中ユーザの場合、親タグをaタグではなくdivタグにする
    - if current_user == user
      - args = [:div, class: "User__listSection--selected"]
    - else
      - args = [:a, class: "User__listSection"]
    = content_tag(*args)
      div = user.name
      div = user.email
```

`send` を使わなくてよくなりますし、これが現状一番スマートな書き方、というところでしょうか。