7

How would you make an erb template that has human readable json?

The following code works, but it makes a flat json file

default.rb

default['foo']['bar'] = { :herp => 'true', :derp => 42 }

recipe.rb

template "foo.json" do
  source 'foo.json.erb'
  variables :settings => node['foo']['bar'].to_json
  action :create
end

foo.json.erb

<%= @settings %>

Similar SO questions
Chef and ruby templates - how to loop though key value pairs?
How can I "pretty" format my JSON output in Ruby on Rails?

Community
  • 1
  • 1
spuder
  • 17,437
  • 19
  • 87
  • 153
  • If your erb is just a single `<%= @something %>` you'd be better off using the [file resource](https://docs.chef.io/resource_file.html). – ZombieDev Jul 31 '15 at 14:13

3 Answers3

9

As pointed out by this SO Answer .erb templates are great for HTML, and XML, but is not good for json.

Luckily, CHEF uses its own json library which has support for this using .to_json_pretty

@coderanger in IRC, pointed out that you can use this library right inside the recipe. This article shows more extensively how to use chef helpers in recipes.

default.rb

# if ['foo']['bar'] is null, to_json_pretty() will error
default['foo']['bar'] = {}

recipe/foo.rb

pretty_settings = Chef::JSONCompat.to_json_pretty(node['foo']['bar'])

template "foo.json" do
  source 'foo.json.erb'
  variables :settings => pretty_settings
  action :create
end

Or more concise as pointed out by YMMV

default.rb

# if ['foo']['bar'] is null, to_json_pretty() will error
default['foo']['bar'] = {}

recipe/foo.rb

template "foo.json" do
  source 'foo.json.erb'
  variables :settings => node['foo']['bar']
  action :create
end

templates/foo.json.erb

<%= Chef::JSONCompat.to_json_pretty(@settings) %>
Community
  • 1
  • 1
spuder
  • 17,437
  • 19
  • 87
  • 153
  • 2
    You should also be able to do this in your erb template: <%= Chef::JSONCompat.to_json_pretty(@settings) %>. I kind of like that because it turns the responsibility of the format of the string into the view logic in the template. YMMV. – lamont Jun 27 '15 at 01:39
6

Something like this would also work:

file "/var/my-file.json" do
  content Chef::JSONCompat.to_json_pretty(node['foo']['bar'].to_hash)
end
sandstrom
  • 14,554
  • 7
  • 65
  • 62
0

<%= Chef::JSONCompat.to_json_pretty(@settings) %> Works like Charm !!

STA
  • 30,729
  • 8
  • 45
  • 59