Access Hash Entries in ERB Template

I’m trying to access hash entries in an ERB template, but the examples in the docs aren’t working.

In my recipe, I have:

my_hash = { :key1 => 'value1', :key2 => 'value2', :key3 => 'value3', :key4 => 'value4' }

template "myfile.txt" do
  source "myfile.txt.erb"
  variables (my_hash)
end

In myfile.txt.erb, I have:

<% %w( key1 key3 ).each do |k| %>
<%= k %>: <%= @k %>
<% end %>

NOTE: I specifically only want to iterate over some of the hash pairs, not all of them.

But this code doesn’t print the value associated with the key in question. (It prints a blank string.)

I’ve also tried accessing the hash value in the ERB template with @my_hash[k.to_sym] but that doesn’t work either.

Try this instead:

<% %w( key1 key3 ).each do |k| %>
<%= k %>: <%= @my_hash[k] %>
<% end %>
1 Like

Hey @David_Petzel, when I try that, I get the following error during kitchen converge:

=============================================================================
           Error executing action `create` on resource 'template[myfile.txt]'
           =============================================================================

           Chef::Mixin::Template::TemplateError
           ------------------------------------
           undefined method `[]' for nil:NilClass

...
           Template Context:
           -----------------
           on line #36
            35: <% %w( key1 key3 ).each do |k| %>
            36: <%= k %>: <%= @my_hash[k] %>
            37: <% end %>

That is likely because you are not passing the variable in properly. Try

variables (my_hash: my_hash) You’ll want to pass the variable in as a hash like that as sort of described in https://docs.chef.io/resource_template.html#variables

I tried that too, but I get this error:

        ================================================================================
         Recipe Compile Error in /tmp/kitchen/cache/cookbooks/my-wrapper-cookbook/recipes/default.rb
         ================================================================================

         SyntaxError
         -----------
         /tmp/kitchen/cache/cookbooks/my-wrapper-cookbook/recipes/my_recipe.rb:41: syntax error, unexpected tLABEL
             variables (my_hash: my_hash)
                                   ^

Sorry about that, wrap it with curly braces, so its like this

variables({ my_hash: my_hash })

That’s not erroring out the kitchen converge run, but it’s not printing the hash values either.

I had to re-add the .to_sym option in the ERB template for the hash values to show up correctly.

So the final (working) product is:

In my recipe:

my_hash = { :key1 => 'value1', :key2 => 'value2', :key3 => 'value3', :key4 => 'value4' }

template "myfile.txt" do
  source "myfile.txt.erb"
  variables({ my_hash: my_hash })
end

In my template:

<% %w( key1 key3 ).each do |k| %>
<%= k %>: <%= @my_hash[k.to_sym] %>
<% end %>

Thanks for your help, @David_Petzel!

Another option is to iterate over an array of symbols (%i) instead of an array of strings (%w).

<% %i( key1 key3 ).each do |k| %>
<%= k %>: <%= @my_hash[k] %>
<% end %>

The symbol (e.g. :key1) has to_s automatically called on it by the ERB in the <%= %>.

Or filter the hash down in the recipe to the keys you actually want in your template.

Recipe:

my_hash = { :key1 => 'value1', :key2 => 'value2', :key3 => 'value3', :key4 => 'value4' }

wanted_in_the_template = %i( key1 key3 )
hash_for_template = my_hash.select { |k,v| wanted_in_the_template.include? k }

template "myfile.txt" do
  source "myfile.txt.erb"
  variables({ pairs: hash_for_template })
end

Template:

<% @pairs.each do |k,v| %>
<%= "#{k}: #{v}" %>
<% end %>

@jcderose

I think this has more to do with understanding erubis and bindings.

To iterate through the hash passing in key/value pairs it is easier to use each_pair rather than each.

In your recipe (I’ve changed the name of the template and am passing your hash in to the template as some_hash)

directory 'c:\temp'

my_hash = { :key1 => 'value1', :key2 => 'value2', :key3 => 'value3', :key4 => 'value4' }

template "c:/temp/myfile.txt" do
  source "mytemplate.txt.erb"
  variables ({
	:some_hash => my_hash
   })
end

In your template (the hash is addressed as some_hash rather than my_hash)

<% @some_hash.each_pair do |k,v| %>
key: <%= k %> Value <%= v %>
<% end %>

Or if you want to format the output

<% @some_hash.each_pair do |k,v| %>
<%= "Key %-20s Value %s" % [k,v] %>
<% end %>

Therefore, to pull out specific values

<% [:key1, :key3].each do |k| %>
key: <%= k %> value: <%= @some_hash[k] %>
<% end %>

If you really want to do it your way then

Recipe

directory 'c:/temp'

my_hash = { :key1 => 'value1', :key2 => 'value2', :key3 => 'value3', :key4 => 'value4' }

template "c:/temp/myfile.txt" do
  source "mytemplate.txt.erb"
  variables (my_hash)
end

Template

<% [@key1, @key3].each do |v| %>
Value is <%= v %>
<% end %>

Produces (with Chef Client 12.8.1)

Value is value1
Value is value3

There is a TemplateContext that Chef uses which is inherited from Erubis::Context, to find out what is available it’s sometimes easier to query self in the template

<%= self.keys %>