1

I am making a view helper to render set of data in a format. I made these classes

require 'app/data_list/helper'

module App
  module DataList
    autoload :Builder, 'app/data_list/builder'
     @@data_list_tag = :ol
     @@list_tag      = :ul
    end
end
ActionView::Base.send :include, App::DataList::Helper

helper is

module App
  module DataList
    module Helper

      def data_list_for(object, html_options={}, &block)

        builder     = App::DataList::Builder
        arr_content = []
        object.each do |o|
          arr_content << capture(builder.new(o, self), &block)
        end
        content_tag(:ol, arr_content.join(" ").html_safe, html_options).html_safe
      end
    end
  end
end

builder is

require 'app/data_list/column'

module App
  module DataList
    class Builder
      include App::DataList::Column
      include ActionView::Helpers::TagHelper
      include ActionView::Helpers::AssetTagHelper

      attr_reader :object, :template

      def initialize(object, template)
        @object, @template = object, template
      end

      protected

      def wrap_list_item(name, value, options, &block)
        content_tag(:li, value).html_safe
      end

    end
  end
end

column module is

module App
  module DataList
    module Column
      def column(attribute_name, options={}, &block)
        collection_block, block = block, nil if block_given?

        puts attribute_name

        value = if block
                  block
                elsif @object.respond_to?(:"human_#{attribute_name}")
                  @object.send :"human_#{attribute_name}"
                else
                  @object.send(attribute_name)
                end

        wrap_list_item(attribute_name, value, options, &collection_block)
      end
    end
  end
end

Now i write code to test it

 <%= data_list_for @contracts do |l| %>
        <%= l.column :age %>
        <%= l.column :contact do |c| %>
            <%= c.column :phones %>
        <% end %>
        <%= l.column :company %>
    <% end %>

Every thing is working fine , age , contact , company is working fine. But phones for the contact is not showing.

Does any one have an idea, i know i have missed something in the code. Looking for your help.

Updated question with complete source is enter link description here

Community
  • 1
  • 1
Nazar Hussain
  • 5,102
  • 6
  • 40
  • 67

2 Answers2

1

There are two issues I can see in the column module.

1) If a block is provided you're setting it to nil - so if block is always returning false. 2) Even if block wasn't nil you're just returning the block as the value, not actually passing control to the block. You should be calling block.call or yielding. Implicit blocks execute faster, so I think your column module should look more like this:

module DataList
  module Column
    def column(attribute_name, options={})

      value = begin
        if block_given?
          yield self.class.new(@object.send(attribute_name), @template)
        elsif @object.respond_to?(:"human_#{attribute_name}")
          @object.send :"human_#{attribute_name}"
        else
          @object.send(attribute_name)
        end
      end

      wrap_list_item(attribute_name, value, options)
    end
  end
end
mnelson
  • 2,992
  • 1
  • 17
  • 19
  • Thanks for the help, but it is generating some error. on line `<%= c.column :phones %>` it generates error `ActionView::Template::Error (undefined method `column' for nil:NilClass):` – Nazar Hussain Mar 29 '11 at 08:44
  • Now error has changed `ActionView::Template::Error (undefined method `phones' for #):` – Nazar Hussain Mar 30 '11 at 11:52
  • Hm, how about `yield self.class.new(@object.send(attribute_name), @template)`? I'm assuming that the contacts that are being passed into `data_list_for` have a `contact` method which returns an object which will respond to `phones`? – mnelson Mar 30 '11 at 14:59
  • Sorry to reply late. The change you suggested is working now... Hurraaa! But it also cause a small issue now, `:phones` are rendering but `:cotnact` do not render. I have to write extra line for it. `<%= data_list_for @leads do |l| %> <%= l.column :age %> <%= l.column :contact %> <%= l.column :contact do |c| %> <%= c.column :phones %> <% end %> <%= l.column :company %> <% end %>` – Nazar Hussain Apr 02 '11 at 03:33
0

The solution is now posted in the discussion.

Community
  • 1
  • 1
Nazar Hussain
  • 5,102
  • 6
  • 40
  • 67