Метод многоуровневого блока создает проблему

у меня есть класс

class DataListBuilder
    include ActionView::Helpers::TagHelper
    include ActionView::Helpers::CaptureHelper
    include ActionView::Helpers::UrlHelper
    attr_accessor :object, :output_buffer

    def initialize(object)
      @object, @output_buffer = object, nil
    end

    def column (&block)
      if block_given?
        content_tag(:li, block.call(self))
      else
        content_tag(:li, "")
      end
    end

    def options_column(&link_block)
      if block_given?
        content_tag(:li, content_tag(:dl, "<dt><a href='#'>&nbsp;</a></dt><dd><ul>#{link_block.call(self)}</ul></dd>".html_safe, :class=>'options'))
      else
        content_tag(:li, "")
      end
    end

    def link_item(title, url, options={})
      content_tag :li, link_to(title, url, options)
    end
  end

и называя это как

<%= l.options_column do |c| %>
        <%= c.link_item 'Show', lead_path(c.object) %>
        <%= c.link_item 'Edit', edit_lead_path(c.object) %>
        <%= c.link_item 'New Note', "leads/#{c.object.id}/notes/new", :class=>"display-newxdoc", :id=>c.object.id %>
        <%= c.link_item 'Create Opportunity', new_lead_opportunity_path(c.object) %>
    <% end %>

желаемый результат

<li><dl class="options"><dt><a href="#">&nbsp;</a></dt><dd><ul style="display: none;">
    <li><a data-remote="true" class="plus" href="leads/details/309">&nbsp;</a></li>
    <li>3w</li>
    <li>Simon Wu</li>
    <li>1-714-553-0888</li>
    <li>[email protected]</li>
    <li>Unified Beat</li>

        <li><a href="/leads/309">Show</a></li>
        <li><a href="/leads/309/edit">Edit</a></li>
        <li><a id="309" class="display-newxdoc" href="leads/309/notes/new">New Note</a></li>
        <li><a href="/leads/309/opportunities/new">Create Opportunity</a></li>

но он генерирует

<li><a href="/leads/309">Show</a></li>
<li><a href="/leads/309/edit">Edit</a></li>
<li><a id="309" class="display-newxdoc" href="leads/309/notes/new">New Note</a></li>
<li><a href="/leads/309/opportunities/new">Create Opportunity</a></li>
<li><dl class="options"><dt><a href="#">&nbsp;</a></dt><dd><ul style="display: none;">
    <li><a data-remote="true" class="plus" href="leads/details/309">&nbsp;</a></li>
    <li>3w</li>
    <li>Simon Wu</li>
    <li>1-714-553-0888</li>
    <li>[email protected]</li>
    <li>Unified Beat</li>

        <li><a href="/leads/309">Show</a></li>
        <li><a href="/leads/309/edit">Edit</a></li>
        <li><a id="309" class="display-newxdoc" href="leads/309/notes/new">New Note</a></li>
        <li><a href="/leads/309/opportunities/new">Create Opportunity</a></li>
</ul></dd></dl></li>
    </ul></dd></dl></li>

Может ли кто-нибудь помочь мне в этом.

Полный код указан здесь.


person Nazar Hussain    schedule 06.04.2011    source источник


Ответы (2)


Прежде всего, мы переработали ваш помощник для более интенсивного использования content_tag (просто чтобы понять, что происходит в этом коде ^_^).

Затем мы добавляем использование output_buffer, которое было определено, но вообще не использовалось в помощнике.

После этого все методы, которые должны вызываться из erb, должны возвращать nil, чтобы они не отображались в HTML.

И последним синтаксическим suger было использование instance_eval, поэтому вам не нужны блоки стиля {|c| ...}. Вы можете использовать все переменные из DataListBuilder прямо там.

module DataListHelper
  def list_headers(args=[])
    args    = Array.new(args)
    columns = []
    args.map { |o| columns << content_tag(:li, o.split(":").first, :style=>"width:#{o.split(":").second}px;") }
    content_tag(:ul, columns.join(" ").html_safe, :class=>"list-headers")
  end

  def data_list_total_records(array)
    content_tag(:div, page_entries_info(array).html_safe, :class=>"total-records")
  end

  def data_list_for(object, headers=[], &block)

    if object.is_a? Array
      if object.length == 0
        list_headers(headers).concat(content_tag(:strong, "<br />No records found".html_safe))
      else
        res_obj = data_list_total_records(object)
        res_obj << content_tag(:ol, :class=>"data-list") do
          res_ol = content_tag(:li) do
            res = list_headers(headers)
            object.each do |o|
              builder = DataListBuilder.new(o)
              res << content_tag(:li) do
                content_tag(:ul, :id=>o.id, :class=>"list-row #{cycle('odd', 'even')}") do
                  capture(builder, &block)
                  builder.output_buffer.html_safe
                end
              end
            end
            res
          end
          res_ol << data_list_pagination(object)
        end
        res_obj
      end
    else
      list_headers(headers).concat(content_tag(:strong, " <br />Not available."))
    end
  end

  class DataListBuilder
    include ActionView::Helpers::TagHelper
    include ActionView::Helpers::CaptureHelper
    include ActionView::Helpers::UrlHelper
    include Rails.application.routes.url_helpers

    attr_accessor :object, :output_buffer, :controller

    def initialize(object)
      @object, @output_buffer = object, ''
    end

    def column (&block)
      @output_buffer << if block_given?
        content_tag(:li, instance_eval(&block))
      else
        content_tag(:li, "")
      end
      nil
    end

    def options_column(&link_block)
      @output_buffer << if block_given?
        content_tag(:li) do
          content_tag(:dl, :class=>'options') do
            res = content_tag(:dt) do
              content_tag(:a, '&nbsp;'.html_safe, :href => '#')
            end
            res << content_tag(:dd) do
              content_tag(:ul) do
                instance_eval &link_block
              end
            end
          end
        end
      else
        content_tag(:li, "")
      end
      nil
    end

    def link_item(title, url, options={})
      content_tag :li, link_to(title, url, options)
    end
  end
end

И твой взгляд стал таким:

<%= data_list_for @leads, [" :10", "Age:30", "Contact:140", "Phone:140", "Email:180", "Company:100", ""] do |l| %>
    <%= l.column { link_to "&nbsp;".html_safe, "leads/details/#{object.id}", :class=>:plus, :remote=>true } %>
    <%= l.column { object.age } %>
    <%= l.column { object.contact.complete_name } %>
    <%= l.column { object.contact.phones.blank? ? "-" : object.contact.phones.first.phone_number } %>
    <%= l.column { object.contact.emails.blank? ? "-" : object.contact.emails.first.email } %>
    <%= l.column { object.company.title } %>
    <%= l.options_column do %>
        <%= link_item 'Show', lead_path(object.id) %>
        <%= link_item 'Edit', edit_lead_path(object.id) %>
        <%= link_item 'New Note', "leads/#{object.id}/notes/new", :class=>"display-newxdoc", :id=>object.id %>
        <%= link_item 'Create Opportunity', new_lead_opportunity_path(object.id) %>
    <% end %>
<% end %>
person Viacheslav Molokov    schedule 06.04.2011
comment
Действительно очень большое спасибо. Оно работает. и это также дало мне полное представление о том, что происходит и внутри. Теперь единственная проблема заключается в том, что методы lead_path(object) и маршрута не работают. Он генерирует ошибки ActionView::Template::Error (undefined method lead_path' для #‹DataListHelper::DataListBuilder:0xef8c3bc›):`. Это единственное, что осталось в списке. Пожалуйста, помогите решить это. - person Nazar Hussain; 07.04.2011
comment
@Nazar Huaain - я обновил ответ, чтобы решить вашу проблему со ссылками. Добавлен include Rails.application.routes.url_helpers и атрибут controller в DataListBuilder. Добавлено object.id в поле зрения. stackoverflow.com/questions/341143/ для получения дополнительной информации - person Viacheslav Molokov; 07.04.2011

options_column - это "блочный вид", я бы удалил = в <%= l.options_column do |c| %>, это точно. Затем я бы использовал concat в options_column вместо того, чтобы возвращать его непосредственно в виде строки.

Во всяком случае, простое решение здесь (я использовал его, никаких проблем):

https://github.com/markevans/block_helpers

person tokland    schedule 06.04.2011
comment
Это действительно здорово. но у меня есть к нему вопрос. Как мы можем сделать такие хелперы блоков, которые перебирают какую-то коллекцию. Я не могу найти ни одного примера или способа на вики предложенного вами помощника. Пожалуйста, пришлите мне любой пример для этого. - person Nazar Hussain; 07.04.2011