How do you pass an array to an erb template in ruby and have it iterated over?

38,225

Solution 1

the basic syntax for using each in ruby is something like this:

array.each do |item_from_array| BLOCK

so if you only had one array then you could just do something like this: (I would use a different name inside the vertical bars for clarity)

<% device.each do |dev| %>
  auto <%= dev %> inet static
<% end %>

However that would iterate over all of your devices first, before moving on to your ipaddr array. I'm guessing you want them each in turn auto, address, netmask, etc. In that case you'd be better off using a more 'traditional' index and looping through N times, like this:

<% for idx in (0..1) %>
  auto <%= device[idx] %> inet static
  address <%= address[idx] %>
  netmask <%= netmask[idx] %>
  broadcast <%= broadcast[idx] %>
<% end %>

Of course you need to think about what your maximum size of array is, and what to do if an array contains less entries than the others. You can find the maximum size of all the arrays by doing something like this: [device,address,netmask,broadcast].map{|a| a.length}.max

and you can skip over a particular array like this: <% if idx < address.length %> address <%= address[idx] %><% end %>

Solution 2

ERB Templates for Dummies

Basic code:

require 'erb'
ERB.new(template).result binding_for_template

What are template and binding_for_template?

Template

Just the template content. You can read it from a file just with a File.read(path).

Binding for template

A binding

encapsulate the execution context at some particular place in the code and retain this context for future use.

How do you use it? Easy:

def binding_for_my_template
  devices      = ["eth0", "br0"]
  ipaddrs      = ["192.168.12.166", "192.168.12.199"]
  netmasks     = ["255.255.255.0", "255.255.255.0"]
  hwaddrs      = ['']
  networks     = ['']
  gateways     = ["192.168.12.254", "192.168.12.204"]
  binding
end

That will return a binding with all six arrays (I changed hwaddr and network to arrays for consistency.

Iterating over arrays

The usual way is using the each method, just like this:

<%- devices.each do |d| %>
  auto <%= d %> inet static
<%- end %>

but there are other methods if you wanna put all in one line, for example devices.join ' ' will join all the strings with a space in between.

Solution 3

You should read the docs. Quoting:

# Managed by Class['ntp']
<% servers_real.each do |server| -%>
server <%= server %>
<% end -%>

# ...

This snippet will iterate over each entry in the array and print it after a server statement, so, for example, the string generated from the Debian template will end up with a block like this:

# Managed by Class['ntp']
server 0.debian.pool.ntp.org iburst
server 1.debian.pool.ntp.org iburst
server 2.debian.pool.ntp.org iburst
server 3.debian.pool.ntp.org iburst
Share:
38,225
matt
Author by

matt

Currently interested in (at work) opensolaris, ZFS, low latency network design, and infiniband. At home, I'm playing with nginx, open source routing, and arduino involving leds and el wire. Experienced and or deadly in the arts of securing and administrating cisco/blade/juniper/voltaire switches, routers, and Windows+linux+unix networks.

Updated on July 09, 2022

Comments

  • matt
    matt almost 2 years

    I need some help with erb templates, I can't seem to get my head around passing an array and then iterating over it. My problem is this. I want to pass a few arrays: `

    device      => ["eth0", "br0"],
    ipaddr      => ["192.168.12.166", "192.168.12.199"],
    netmask     => ["255.255.255.0", "255.255.255.0"], 
    hwaddr      => '',
    network     => '',
    gateway     => ["192.168.12.254", "192.168.12.204"],                                                                                                                
    

    To a template that iterates over each item in the array and prints it out:

    auto <%= device %> inet static                                                                                                                                        
    address <%= ipaddr %>
    netmask <%= netmask %>
    broadcast <%= broadcast %>
    gateway <%= gateway %>
    

    As far as I can get so far is figuring out that I need to do something with device.each |device| puts device, but I don't know what the syntax is supposed to look like. I believe you can tell what I'm trying to do from these snippets, and then you might understand that the entries need to be seperate, and not interpolated. Any help you can offer would be appreciated. I know I should be trying things out in irb and figuring them out from there, which is what I'm reading up on now.

    Thanks!