最近、Rails製自社サービスのリファクタリングとして、viewに書いていたロジックをdecoratorに移行させる作業を行っているのですが、htmlタグの生成方法に悩んでおります。
content_tagは使いたくない
Railsには、htmlタグを生成する汎用的なヘルパーメソッドとして、"content_tag" があります。
例えば以下のような感じでhtmlを生成することができます。
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
↓
<div>
<h3>タイトル</h3>
<p>テキスト</p>
<ul>
<li>リスト1</li>
<li>リスト2</li>
<li>リスト3</li>
</ul>
</div>
便利なメソッドではあるのですが、htmlの構造が複雑になるにしたがって、非常に見づらいし助長な感じになってしまいます。
nokogiriのHtmlBuilderを使えばキレイに書けそう
様々な手段を検討してみたのですが、nokogiriのHtmlBuilderを使うのがベターだと感じました。
HtmlBuilderを使えば、上記のhtmlを、以下のように記述することができます。
root = Nokogiri::HTML::DocumentFragment.parse('')
Nokogiri::HTML::Builder.with(root) do |t|
t.div do
t.h3 'タイトル'
t.p 'テキスト'
t.ul do
t.li 'リスト1'
t.li 'リスト2'
t.li 'リスト3'
end
end
end
構造が分かりやすく、非常に読みやすいです。
モジュールにラップして使う
自社サービスに適用することを想定して、モジュール化してみます。
module HtmlBuilder
def to_html
root = Nokogiri::HTML::DocumentFragment.parse('')
Nokogiri::HTML::Builder.with(root) do |tag|
yield tag
end
root.to_html.html_safe
end
end
そして、decoratorとかの中で呼び出します。
def tableA_tag
to_html do |t|
t.div do
t.h3 'タイトル'
t.p 'テキスト'
t.ul do
t.li 'リスト1'
t.li 'リスト2'
t.li 'リスト3'
end
end
end
end
class指定方法が便利
HtmlBuilderで生成するtagにclassを指定すには、2通りの方法があります。
まずは普通に、
t.h3 'タイトル', class: 'class_name'
とかする方法です。もう一つはtag名の後に直接追加する方法で、
t.h3.class_name 'タイトル'
こんな感じでも記述できます。
これなら、slimやhamlの記述方法とほぼ同じなので、とても直感的で無駄がありません。
最後に
nokogiriはhtmlスクレイパーとして有名ですが、htmlビルダーとしてはあまり知られていないのでしょうか。ググって見たのですが、HtmlBuilderの情報は想像以上に少なかったです。個人的にはとても便利だと思ったのですが、何か欠点とかあるのかしら?