88

I'm trying to nest content tags into a custom helper, to create something like this:

<div class="field">
   <label>A Label</label>
   <input class="medium new_value" size="20" type="text" name="value_name" />
</div>

Note that the input is not associated with a form, it will be saved via javascript.

Here is the helper (it will do more then just display the html):

module InputHelper
    def editable_input(label,name)
         content_tag :div, :class => "field" do
          content_tag :label,label
          text_field_tag name,'', :class => 'medium new_value'
         end
    end
end

<%= editable_input 'Year Founded', 'companyStartDate' %>

However, the label is not displayed when I call the helper, only the input is displayed. If it comment out the text_field_tag, then the label is displayed.

Thanks!

christo16
  • 4,843
  • 5
  • 42
  • 53

4 Answers4

163

You need a + to quick fix :D

module InputHelper
  def editable_input(label,name)
    content_tag :div, :class => "field" do
      content_tag(:label,label) + # Note the + in this line
      text_field_tag(name,'', :class => 'medium new_value')
    end
  end
end

<%= editable_input 'Year Founded', 'companyStartDate' %>

Inside the block of content_tag :div, only the last returned string would be displayed.

rfunduk
  • 30,053
  • 5
  • 59
  • 54
PeterWong
  • 15,951
  • 9
  • 59
  • 68
  • 1
    Typo (in comment only, but slightly confusing) - "Not*e* the + in this line" – Chowlett Nov 17 '10 at 15:15
  • After adding that in, I get syntax error: syntax error, unexpected tIDENTIFIER, expecting kDO or '{' or '(' text_field_tag name,'', :class => 'medium new_value' ^ – christo16 Nov 17 '10 at 15:16
  • 2
    This feels dirty... is that because it's an anti-pattern for a helper to build multiple content tags? – Erik Trautman Sep 26 '14 at 07:33
  • Didn't work for me, had to use `concat` like the other answers suggest – Dex Aug 17 '18 at 10:20
60

You can also use the concat method:

module InputHelper
  def editable_input(label,name)
    content_tag :div, :class => "field" do
      concat(content_tag(:label,label))
      concat(text_field_tag(name,'', :class => 'medium new_value'))
    end
  end
end

Source: Nesting content_tag in Rails 3

lmika
  • 1,725
  • 16
  • 23
  • This worked for me as long as the concat line was on 1 line. I didn't spend long playing with it, though, so there's probably a way to do it multi-line – TerryS Sep 23 '13 at 12:21
  • this will be a better way considering the html_safe issue. using `+` between non-htmlsafe string will make everything non-htmlsafe – Tian Chen Aug 21 '17 at 14:15
  • If you are inside a form builder class, it should be `@template.concat` – elquimista Oct 11 '18 at 22:43
  • I think it's a cleaner solution way to do than `+`. More readable and Rubocop doesn't like `+` – cercxtrova Feb 04 '19 at 15:03
4

I use a variable and concat to help with deeper nesting.

def billing_address customer
  state_line = content_tag :div do
    concat(
      content_tag(:span, customer.BillAddress_City) + ' ' +
      content_tag(:span, customer.BillAddress_State) + ' ' +
      content_tag(:span, customer.BillAddress_PostalCode)
    )
  end
  content_tag :div do
    concat(
      content_tag(:div, customer.BillAddress_Addr1) +
      content_tag(:div, customer.BillAddress_Addr2) +
      content_tag(:div, customer.BillAddress_Addr3) +
      content_tag(:div, customer.BillAddress_Addr4) +
      content_tag(:div, state_line) +
      content_tag(:div, customer.BillAddress_Country) +
      content_tag(:div, customer.BillAddress_Note)
    )
  end
end
Sean M
  • 1,990
  • 20
  • 16
2

building nested content tags with iteration is a little different and gets me every time... here is one method:

      content_tag :div do
        friends.pluck(:firstname).map do |first| 
          concat( content_tag(:div, first, class: 'first') )
        end
      end
Sean M
  • 1,990
  • 20
  • 16