Zagnieżdżone bloki - jak?

Hej,

robię sobie helpery do UI, i chciałbym móc korzystać z następującej składni w widokach do wygenerowania “kontrolki” z zakładkami:

http://paste-it.net/public/uafe7f3/

Stworzyłem więc testowo w oderwaniu od RoR taki kod:

http://paste-it.net/public/l12e51c/

i wygląda na to, że działa, puts wyświetla [#<UI::Tabs::TabBuilder:0x7fb1150fe8d0 @body="content1", @name="AA">, #<UI::Tabs::TabBuilder:0x7fb1150fe7b8 @body="content2", @name="name-special2">]
Dodanie do tego generowania HTML to już banał.

Po przeniesieniu do RoR są jednak problemy, oto kod ApplicationHelper: http://paste-it.net/public/te3d286/

W kodzie HTML pojawia się

[code] B

  Bb


  D

  Dd[/code]

czyli zawartość bloków. A co jeszcze dziwniejsze, zachowują się one tak jakby kumulowały swoje poprzednie wywołania bo puts bulder.tabs.inspect zwraca

[#<UI::Tabs::TabBuilder:0x7fd3ffb956b0 @body="Aa", @name="A">, #<UI::Tabs::TabBuilder:0x7fd3ffb940a8 @body="\n B\n\n Bb\n\n\n D\n\n Dd\n\n", @name="\n B\n\n Bb\n\n\n D\n\n Dd\n\n">, #<UI::Tabs::TabBuilder:0x7fd3ffb92050 @body="Cc", @name="C">, #<UI::Tabs::TabBuilder:0x7fd3ffb90840 @body="\n B\n\n Bb\n\n\n D\n\n Dd\n\n", @name="\n B\n\n Bb\n\n\n D\n\n Dd\n\n">]
(zwróć uwagę na to, że @body zawiera i Bb i Dd - wywołania z zupełnie różnych bloków)

Gdzie szukać przyczyny?

Czemu jest taka rozbieżność między “gołym” rubym a RoR?

Z góry dziękuję za pomoc.

Pierwszą moją uwagą jest, aby znaczniki ERB znajdowały się tylko na początku i na końcu kodu:
http://paste-it.net/public/o2b95f5/
a zamiast puts po prostu zwróć rezultat w postaci stringa. Kod wewnątrz bloków ERB jest analizowany w bardzo specyficzny sposób, dlatego w tym przypadku daje nieoczekiwane rezultaty.

puts jest tylko do testów…

czy jesteś w stanie przybliżyć, co znaczy “bardzo specyficzny sposób”?

Chcę mimo wszystko zachować taką składnię, bo jest naturalna dla szablonów w ERb.

Bloków w railsach 2.x niestety nie można pisać w ten sam sposób, w który pisałbyś bloki dla zwykłego rubiego.

Zobacz na przykładowy kod helpera przyjmującego blok:

def sidebar?(&block) block_output = capture(@argument_for_block, &block) concat("<div>") concat(block_output) concat("</div>") end
Nie mam teraz czasu sprawdzać co jest nie tak w Twoim kodzie, ale spróbuj zamienić Twoje metody tak, żeby korzystały z helperów capture i concat (więcej znajdziesz w dokumentacji).

Jak widzisz ERB wypisuje to, co jest luzem w stronie. Formalnie działa to tak: ERB zamienia każdy ciąg występujący poza <% %> jako @body.concat(zawartość bloku). Jeśli taki kod zostanie wywołany to jego efekty lądują w buforze strony. Jeśli we własnym builderze chcesz tylko zapamiętać zawartość bloku i nie wypisywać go od razu to użyj helpera capture (http://apidock.com/rails/ActionView/Helpers/CaptureHelper/capture).

Dwie uwagi:

To akurat mocna pomyłka. Proponuję Ci jednak wrzucić wszystko w jeden blok albo jeszcze lepiej w helper.

[quote=pardon]<%- tabs do |t| -%>
<%- t.tab do |tt| -%>
<%- tt.name = “A” -%>
<%- tt.body = “Aa” -%>
<%- end -%>[/quote]
To API mocno ssie :slight_smile: Co powiesz na:

tabs do |tabs| tabs.tab("Main", link_to("Home", home_path)) tabs.tab do |tab| "Some more content" end end
Napisz jaki efekt semantyczny chcesz uzyskać bo na razie twoje API wygląda na mocno na wyrost napisane i łamiące YAGNI.