croceldon
croceldon

Reputation: 4615

How to nest Rails tag in a helper?

Using Rails 6.1, trying to nest content inside a helper method with:

tag.div do
  concat tag.span 'Options: ', class: 'small'
  concat tag.span do
    doc.options.each do
      concat option.title
    end
  end
end

I was expecting this to return a div with two spans inside it, the first of which has the "Options" string, the second of which has the titles for all the options. But this doesn't work. I wind up with:

<div>
  <span class="small">Options: </span>
  <span></span>
</div>

The last span is blank. How can I get this working?

Upvotes: 0

Views: 503

Answers (1)

Cassandra S.
Cassandra S.

Reputation: 770

The reason this doesn't work is... I'm not entirely sure. There is some weird stuff going on between concat and tag, that's for sure:

:0> tag.div do
:1*   tag.span { "A" }
:1> end
=> "<div><span>A</span></div>"

# But:
:0>tag.div do
:1*   tag.span { "A" }
:1>   tag.span { "B" }
:1> end
=> "<div><span>B</span></div>"

# But also:
:0> tag.div do
:1*   concat tag.span { "A" }
:1>   concat tag.span { "B" }
:1> end
=> "<div><span></span><span></span></div>"

:0> helper.tag.div do
:1*   concat tag.span { concat "A" }
:1>   concat tag.span { concat "B" }
:1> end
=> "<div><span>A</span><span>B</span></div>"

# For completeness:
:0> tag.div do
:1*   concat tag.span "A"
:1>   concat tag.span "B"
:1> end
=> "<div><span>A</span><span>B</span></div>"

Perhaps someone better versed in Rails can explain it better. But I can offer you a solution.


Or rather, I don't know what you want to achieve, but you can do something like this:

tag.div do
  concat tag.span "A"
  concat tag.span([1, 2, 3].join(" "))
end

That will give you <div><span>1 2 3</span></div>. You can also do away with the concat entirely:

tag.div do
  tag.span "A"
  tag.span([1, 2, 3].join(" "))
end

But if you want each title as its own span, you're doing it the wrong way around:

:0> tag.div do
:1*   concat tag.span "A"
:1>   ["B", "C"].each { |c| concat tag.span c }
:1> end
=> "<div><span>A</span><span>B</span><span>C</span></div>"

Finally; there's no reason to use a helper for this kind of static html; this would be better served in an erb or haml file:

<span class="small">Options</span>
<% doc.options.each do |option| %>
  <span><%= option.title %></span>
<% end %>

Upvotes: 2

Related Questions