RailsのSlim-Templateで木構造をやっていく。
追記 結果が正確になっていなかったと教えていただいたので後日修正します。
追記2 書き直しました。ついでに木になってなかったのも直しました。ちなみにコメント欄で @jnchito さんに教えてもらったpartial
を使う方法が目からウロコでかなりよかったです。
木構造はプログラミングで避けて通れないデータ構造です。最近木構造づいてます。
しかし描画となると、いろいろなアレがあります。
capture
を使ったりしますが、使わなかったりもします。
- Rails 5.0.0
- Slim 3.0.7
データ
@tree =
{
title: :a,
children: [
{
title: :a_a
},
{
title: :a_c,
children: [
{
title: :a_c_a
},
{
title: :a_c_b,
children: [
{
title: :a_c_b_a
}
]
},
{
title: :a_c_c
}
]
},
{
title: :a_a
}
]
}
できあがり
1. a
1. a_a
2. a_c
1. a_c_a
2. a_c_b
1. a_c_b_a
3. a_c_c
3. a_a
素朴にslim
で書く
ol
li
= @tree[:title]
- if @tree[:children]
ol
- @tree[:children].each do |c2|
li
= c2[:title]
- if c2[:children]
ol
- c2[:children].each do |c3|
li
= c3[:title]
- if c3[:children]
ol
- c3[:children].each do |c4|
li= c4[:title]
つらいですね。
これを書くために何回かインデント位置を間違えたし、深まるとどうにもなりません。
だったらHelper
だ
views
描画の支援メソッドを書くために、hoge_helper
というのが用意されています。
# helper側
def write_tree(tree)
return unless tree
children = (tree[:children] || []).map { |child|
write_tree(child)
}.join.html_safe
"<li>#{tree[:title]}<ol>#{children}</ol></li>".html_safe
end
# slim側
ol
= write_tree(@tree)
書けましたし深さも関係ありませんが、せっかくslim
を使っているのに、ベタなHTMLやtag_helper
の類は書きたくありません。
まぁcapture
なんですけども
みなさんご存知の通り、helper
に書かれたメソッドは、テンプレート側で&block
に渡されたテンプレートを描画できます。
ところで、capture
は&block
以外にも引数を取れるんです。
# helper側
def write_capture_tree(tree, proc = nil, &block)
return unless tree
pass = block ? block : proc
capture(tree[:title], tree[:children], pass, &pass)
end
# slim側
ol
= write_capture_tree(@tree) do |title, children, proc|
li
= title
- if children
ol
- children.each do |child|
= write_capture_tree(child, proc)
この場合では、chilD
やpass
で、content
とproc
でslim
側に渡されるやつです。
ブロック内で呼ばれたhelper
のメソッドに、再度slim
が入ったブロックと、次の子供をわたすことによって、HTMLはslim
で書いて、木構造を描画できることとなりました。
capture
の処理自体に&block
を使ってしまうため、あらためてblock
的なものを渡すためにpass
変数が必要になりました。
木構造が描画できて嬉しいですが、一抹の悲しさがあります。
slim
かつcapture
を使わない場合
消しました。