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!