Может ли Rails helper_method использовать yield, как если бы он был вызван в соответствующем представлении? - PullRequest
0 голосов
/ 03 мая 2020

У меня есть следующий аккордеонный генератор, который прекрасно работает, когда включен непосредственно в представление:

<%
def collapser(name)
  fad = {
    class: 'collapsed',
    data: {toggle: 'collapse', parent: '#accordion_id'},
    href: "##{name}",
    aria: {expanded: 'true', controls: name}
  }
  tag.div(class: 'panel panel-default') do
    tag.div(class: 'panel-heading', role: 'tab') do
      tag.p(class: 'panel-title') do
        tag.a(fad) do
          tag.span do
            t("section.#{name}.title")
          end
        end
      end
    end +
    tag.div(id: name, class: 'panel-collapse collapse', role: 'tabpanel', style: 'height: 0px;', aria: {labelledby: name}, data: {parent: '#accordion_id'}) do
      tag.div(class: 'panel-body') do
        tag.div(class: 'uncode_text_column') do
          yield
        end
      end
    end
  end
end
%>

<%= tag.div(id: 'accordion_id', class: 'panel-group', role: 'tablist', aria: {multiselectable: 'true'}) do %>    
    <%= collapser('example') do %>
      <%= tag.p t('section.example.nub.row1') %>
    <% end %>
<% end %>

Теперь я хотел перейти к более чистой реализации:

  • Перемещение collapser к соответствующему контроллеру
  • сделать generic_collapser(name, parent), чтобы
    • был более широкодоступен в другой части базы кода
    • этот спецификатор c может быть реализован как вызов generic_collapeser(name, 'accordion_id')

Но я застрял на первом шаге, так как не могу правильно обработать изменение контекста. Во-первых, tag больше не доступен, но простое назначение tag = view_context.tag, кажется, делает эту работу. Однако я не нашел способ транспонировать оператор yield. Я попробовал следующее

  • keep tag.div(class: 'uncode_text_column') { yield }
  • use tag.div(class: 'uncode_text_column') { view_contex{yield} }
  • use tag.div(class: 'uncode_text_column') { view_contex(&block) } вместе с def collapser(name, &block)

Но никто не дал ожидаемого результата.

Подсказки к хорошим ресурсам для лучшего понимания view_context, yield и управления блоками также приветствуются, особенно учебник с упражнениями.

Что это и блок в Ruby? И как это передается в методе здесь?

1 Ответ

0 голосов
/ 03 мая 2020

Итак, ключевая особенность, которую следует использовать здесь - это метод capture. Вот как это было использовано для решения этой проблемы, как было указано в вопросе:

<% # in the view %>
<% content[:section_1] = capture do %>
  <%= tag.ul do %>
    <%= tag.li item 1 %>
    <%= tag.li item 2 %>
    <%= tag.li item 3 %>
  <% end %>
<% end %>

<% content[:section_2] = capture do %>
  <%= tag.p 'some paragraphe %>
<% end %>

<% bib = "accordion_#{SecureRandom.hex}" %>
<% title = ->(name){t("section.#{name}.title")} %>
<%= tag.div(id: bib, class: 'panel-group', role: 'tablist', aria: {multiselectable: 'true'}) do %>
  <% content.each do |key, nub| %>
    <%= collapser(key, title[key], nub, bib) %>
  <% end %>
<% end %>

А с другой стороны

  # Within helpers
  # Returns a collapsable html div usable as an accordion item
  # Params:
  # +name+:: identifier for this div
  # +title+:: text used as title of the collapsable div
  # +content+:: text used as contont of the collapsable div
  # +parent+:: identifier of the parent accordion div
  def collapser(name, title, content, parent)
    link_fad = {
      class: 'collapsed',
      data: {toggle: 'collapse', parent: "##{parent}"},
      href: "##{name}",
      aria: {expanded: 'true', controls: name}
    }
    content_fad = {
      id: name,
      class: 'panel-collapse collapse',
      role: 'tabpanel',
      style: 'height: 0px;',
      aria: {labelledby: name},
      data: {parent: "##{parent}"},
    }
    tag.div(class: 'panel panel-default') do
      tag.div(class: 'panel-heading', role: 'tab') do
        tag.p(class: 'panel-title') do
          tag.a(link_fad) do
            tag.h2 do
              title
            end
          end
        end
      end + # note the plus here so we return a single string with the whole HTML
      tag.div(content_fad) do
        tag.div(class: 'panel-body') do
          tag.div(class: 'uncode_text_column' ) do
            content
          end
        end
      end
    end
  end
...