LoginSignup
9
6

More than 5 years have passed since last update.

content_tagを美しく多段階ネストしたい場合はどうする?

Last updated at Posted at 2016-07-27

content_tagへの不満

私が今関わっているRails製サービスでは、viewに直接ロジックが書かれている部分が多いため、helperやdecoratorに処理の移行を進めています。しかし、うちのチームにはRails有識者がいないため、view生成周りのベストプラクティスが分かりません。今日はcontent_tagの使い方で悩みました。

例えば、以下のようなhtmlがあるとします。

<div>
  <h3>タイトル</h3>
  <p>テキスト</p>
  <ul>
    <li>リスト1</li>
    <li>リスト2</li>
    <li>リスト3</li>
  </ul>
</div>

これを、単純にcontent_tagで生成するとしたら、以下のように書けます。

content_tag(:div) do
  concat content_tag(:h3, 'タイトル')
  concat content_tag(:p, 'テキスト')
  concat(
    content_tag(:ul) do
      concat content_tag(:li, 'リスト1')
      concat content_tag(:li, 'リスト2')
      concat content_tag(:li, 'リスト3')
    end
  )
end

特定のタグ配下にに複数の要素を挿入する場合は、ブロック内でconcatに渡します。
しかし、ここで些細な問題が発生します。それは・・・

concatにブロック付きのcontent_tagを渡すには、カッコで囲まなければいけない

ということです。以下の部分ですね。

concat(
  content_tag(:ul) do
    ~中略
  end
)

この記法は非常に見づらいので、できるなら使いたくありません。

どうすれば?

ケースバイケースなので最適解はないかもしれませんが、自分が思いついたのは次のような方法です。

まず、ブロック付きで呼び出すcontent_tagに代わるメソッドを定義します。

def content_tag_push(type, *option)
  tags = []
  yield tags
  content_tag(type, tags.reduce(:+), *option)
end

先ほどの例を、上記のメソッドを使って置き換えると以下のようになります。

content_tag_push(:div) do |div|
  div << content_tag(:h3, 'タイトル')
  div << content_tag(:p, 'テキスト')
  div << content_tag_push(:ul) do |ul|
           ul << content_tag(:li, 'リスト1')
           ul << content_tag(:li, 'リスト2')
           ul << content_tag(:li, 'リスト3')
         end
end

個人的にはこちらのほうが統一感があって好きなのですが、どうなのでしょう・・・

最後に

もっとマシな方法がある気がします。そもそも、ネストが深い場合は適度に処理を分けるべきなので、こんなこと真面目に考える必要ないかも。

9
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6