Multi level block method is generating issue

本小妞迷上赌 提交于 2019-11-30 00:13:55

问题


I have a class

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

and calling it as

<%= 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 %>

the desired output is

<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>omnisw@unifiedbeat.com</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>

but it is generating

<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>omnisw@unifiedbeat.com</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>

Can any one help me in it.

Complete code is listed here.


回答1:


First of all we refactored your helper for more intensive usage of content_tag (just to get whats going in this code ^_^).

Next we add usage of output_buffer which was defined but not used at all in helper.

After it all methods wich should be called from erb should return nil so they didn't appear in HTML.

And last syntactic suger was usage of instance_eval so you don't need {|c| ...} style blocks. You can use all variables from DataListBuilder directly there.

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

And your view became this:

<%= 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 %>



回答2:


options_column is a "block view", I'd remove the = in <%= l.options_column do |c| %>, that's for sure. Then, I'd use concat in options_column instead of returning it directly as a string.

Anyway, the simple solution is here (I've used it, no problems at all):

https://github.com/markevans/block_helpers



来源:https://stackoverflow.com/questions/5562658/multi-level-block-method-is-generating-issue

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!