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 %>
jcderose:
variables (my_hash)
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 template Resource
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 %>