How to get if or unless statement to work over multiple lines in erb template

3.3k views Asked by At

I'm trying to write in some logic to a erb template in a chef cookbook. I have the following, which I thought would work. At the moment the attribute there is nil, but it's not skipping the whole block like I thought it would. How do I get the top statement to cause the template reader to skip the whole block?

    <% unless node['base']['logstash-forwarder']['nginx'].nil? %>
      <%= "{" %>
      <%= "\"paths\": [" %>
      <% node['base']['logstash-forwarder']['nginx'].each do |path| %>
        <% unless path.equal? node['base']['logstash-forwarder']['nginx'].last %>
        <%= "\"#{path}\"," %>
        <% end %>
      <% end %>
    <%= "\"#{node['base']['logstash-forwarder']['nginx'].last}\"" %>
    <%= " ]," %>
    <%= "\"fields\": { \"type\": \"nginx-access\" }" %>
    <%= "}" %>
  <% end %>
1

There are 1 answers

0
smathy On

Your exact code above works precisely as expected in ERB, see:

[122] pry(main)> e = ERB.new <<'EOI'
[122] pry(main)*  <% unless node['base']['logstash-forwarder']['nginx'].nil? %>
[122] pry(main)*       <%= "{" %>
[122] pry(main)*       <%= "\"paths\": [" %>
[122] pry(main)*       <% node['base']['logstash-forwarder']['nginx'].each do |path| %>
[122] pry(main)*         <% unless path.equal? node['base']['logstash-forwarder']['nginx'].last %>
[122] pry(main)*         <%= "\"#{path}\"," %>
[122] pry(main)*         <% end %>
[122] pry(main)*       <% end %>
[122] pry(main)*     <%= "\"#{node['base']['logstash-forwarder']['nginx'].last}\"" %>
[122] pry(main)*     <%= " ]," %>
[122] pry(main)*     <%= "\"fields\": { \"type\": \"nginx-access\" }" %>
[122] pry(main)*     <%= "}" %>
[122] pry(main)*   <% end %>
[122] pry(main)* EOI
=> #<ERB:0x007fe74bb35ff8
 @encoding=#<Encoding:UTF-8>,
 @filename=nil,
 @lineno=0,
 @safe_level=nil,
 @src=
  "#coding:UTF-8\n_erbout = ''; _erbout.concat \" \";  unless node['base']['logstash-forwarder']['nginx'].nil? ; _erbout.concat \"\\n      \"\n; _erbout.concat(( \"{\" ).to_s); _erbout.concat \"\\n      \"\n; _erbout.concat(( \"\\\"paths\\\": [\" ).to_s); _erbout.concat \"\\n      \"\n;  node['base']['logstash-forwarder']['nginx'].each do |path| ; _erbout.concat \"\\n        \"\n;  unless path.equal? node['base']['logstash-forwarder']['nginx'].last ; _erbout.concat \"\\n        \"\n; _erbout.concat(( \"\\\"\#{path}\\\",\" ).to_s); _erbout.concat \"\\n        \"\n;  end ; _erbout.concat \"\\n      \"\n;  end ; _erbout.concat \"\\n    \"\n; _erbout.concat(( \"\\\"\#{node['base']['logstash-forwarder']['nginx'].last}\\\"\" ).to_s); _erbout.concat \"\\n    \"\n; _erbout.concat(( \" ],\" ).to_s); _erbout.concat \"\\n    \"\n; _erbout.concat(( \"\\\"fields\\\": { \\\"type\\\": \\\"nginx-access\\\" }\" ).to_s); _erbout.concat \"\\n    \"\n; _erbout.concat(( \"}\" ).to_s); _erbout.concat \"\\n  \"\n;  end ; _erbout.concat \"\\n\"\n; _erbout.force_encoding(__ENCODING__)">
[123] pry(main)> node = { 'base' => { 'logstash-forwarder' => {}}}
=> {"base"=>{"logstash-forwarder"=>{}}}
[124] pry(main)> path = nil
=> nil
[125] pry(main)> e.result binding
=> " \n"
[126] pry(main)> 

So the problem is either that Chef does something weird (seems unlikely) or your node isn't as nil? as you think it is.

Update

Reading between the lines, especially at your .each and .last calls, could it be possible that your node['base']['logstash-forwarder']['nginx'] is not actually nil but rather []?

If so, change your .nil? check to a .empty?