I had something I was doing repetitively in an ERb template today and I figured I’d DRY it up by making a helper. Specifically, I was trying to output some given HTML unless a condition was met that should generate a hidden field instead—this case calls for handcrafted HTML generation.
I was doing things like:
<% ignore_these_fields = ['foo', 'bar'] %>
<% unless ignore_these_fields.include?('abc') %>
<input type="text" name="abc" value="<%= @vals['abc'] %>" />
<% else %>
<input type="hidden" name="abc" value="<%= @vals['abc'] %>" />
<% end %>
<% unless ignore_these_fields.include?('foo') %>
<input type="radio" name="foo" value="<%= @vals['foo'] %>" /> One
<input type="radio" name="foo" value="<%= @vals['foo'] %>" /> Two
<% else %>
<input type="hidden" name="foo" value="<%= @vals['foo'] %>" />
<% end %>
<% unless ignore_these_fields.include?('bar') %>
<select name="bar">
<option <% 'selected' if @vals['bar']=='a'%>>blah1</option>
<option <% 'selected' if @vals['bar']=='b'%>>blah2</option>
<option <% 'selected' if @vals['bar']=='c'%>>blah3</option>
</select>
<% else %>
<input type="hidden" name="foo" value="<%= @vals['bar'] %>" />
<% end %>
Here, fairly different HTML form fields get rendered for each type of fields, and in some cases we do not want to show certain fields. So I wanted to do this instead: write a helper that would take a block and render its contents verbatim, otherwise create a hidden field.
<% ignore_these_fields = ['foo', 'bar'] %>
<% render_unless_ignored(ignore_these_fields, 'abc') do %>
<input type="text" name="abc" value="<%= @vals['abc'] %>" />
<% end %>
<% render_unless_ignored(ignore_these_fields, 'foo') do %>
<input type="radio" name="foo" value="<%= @vals['foo'] %>" /> One
<input type="radio" name="foo" value="<%= @vals['foo'] %>" /> Two
<% end %>
<% render_unless_ignored(ignore_these_fields, 'bar') do %>
<select name="bar">
<option <% 'selected' if @vals['bar']=='a'%>>blah1</option>
<option <% 'selected' if @vals['bar']=='b'%>>blah2</option>
<option <% 'selected' if @vals['bar']=='c'%>>blah3</option>
</select>
<% end %>
That’s a bit DRYer. But here came the tricky part: the helper. I had done what I thought was right:
def render_unless_ignored (ignoring_array, key)
unless ignoring_array.include?(key)
yield
else
%Q{<input type="hidden" name="#{CGI::escapeHTML key}" value="#{CGI::escapeHTML @vals[key]}" />}.html_safe
end
end
The yielded content was showing up but the string result was not! The ERb template was not outputting it. Then a colleague pointed out that in this case we need to tell the ERb template to render the string with concat():
def render_unless_ignored (ignoring_array, key)
unless ignoring_array.include?(key)
yield
else
concat %Q{<input type="hidden" name="#{CGI::escapeHTML key}" value="#{CGI::escapeHTML @vals[key]}" />}.html_safe
end
end
And THAT worked!