Search code examples
ruby-on-railsviewruby-on-rails-4helpercontent-tag

content_tag behavior different in view and helper


Someone can explain me why content_tag have a different behavior in view and helpers? A simple code like the one below returns (1) when in the view, but (2) when in the Helper.

  arr = ["a", "b", "c"]
  concat content_tag(:ul, :class => 'a class') do
    arr.each do |item|
      concat content_tag(:li, item)
    end
  end

(1)

<ul class="a class">
  <li>a</li>
  <li>b</li>
  <li>c</li>
</ul>

(2)

<ul>{:class=&gt;"a class"}</ul>

When using content_tag(:ul, '', :class => 'a class') in the Helper, it renders <ul class="a class"></ul>. Why this different behavior too?

The content_tag's behavior is very confusing. I tried some magic with the capture (another confusing method!) method, but without any success.

So... any ideas?

PS.: I'm using rails 4

-------------edit--------------

Since my example is really bad, what I'm really trying to do is somethind like that:

  def language_dropdown
    content_tag :li, class: "dropdown language" do
      concat content_tag(:a, content_tag(:span, I18n.locale, class: "username"),
                     class: "dropdown-toggle", data: { toggle: "dropdown", hover: "dropdown", "close-others" => "true" } )

      concat( content_tag(:ul, class: "dropdown-menu") do
        I18n.available_locales.each do |locale|
          if locale != I18n.locale
            locale_key = "translation.#{locale}"
            content_tag :li do
              concat(link_to I18n.t(locale_key), url_for(locale: locale.to_s))
            end
          end
        end
      end)
    end.html_safe
  end

Solution

  • This works form me...

    module ApplicationHelper
      def some_helper arr
        content_tag(:ul, :class => 'a class') do
          arr.each do |item|
            concat(content_tag(:li, item))
          end
        end
      end
    end
    

    Remove concat from first content_tag and add brackets into the inner concat method.

    Update:

    content_tag :li, class: "dropdown language" do
      concat(content_tag(:a,content_tag(:span, I18n.locale, class: "username"),
        class: "dropdown-toggle", data: { toggle: "dropdown", hover: "dropdown", "close-others" => "true" }))
      concat(content_tag(:ul, class: "dropdown-menu"){
        I18n.available_locales.each do |locale|
          if locale != I18n.locale
            locale_key = "translation.#{locale}"
            concat(content_tag(:li){link_to(I18n.t(locale_key), url_for(locale: locale.to_s))})
          end
        end
      })
    end
    

    The same thing, you need to add brackets and remove the first concat to your code...

    Update 2:

    items = ""
    I18n.available_locales.each do |locale|
      if locale != I18n.locale
        locale_key = "translation.#{locale}"
    
        items += content_tag(:li) do
          link_to(I18n.t(locale_key), url_for(locale: locale.to_s))
        end
      end
    end
    
    label = content_tag(:span, I18n.locale, class: "username")
    link = content_tag(:a, label, class: "dropdown-toggle",
        data: { toggle: "dropdown", hover: "dropdown", "close-others" => "true" })
    
    content_tag :li, class: "dropdown language" do
      concat(link)
      concat(content_tag(:ul, class: "dropdown-menu"){ items.html_safe })
    end