0

I am trying to iterate over a JSON parsed hash table (that has nested Array's of hashes) and insert into a Text Table . The JSON parsed code that I am trying to iterate over is:

{"server"=>{"security_groups"=>[{"name"=>"default"}], "adminPass"=>"LhXEPMkYmqF7",   "id"=>"82b7e32b-f62b-4106-b499-e0046250229f", "links"=>[{"href"=>"http://10.30.1.49:8774/v2/89fc0b9d984d49fba5328766e923958f/servers/82b7e32b-f62b-4106-b499-e0046250229f", "rel"=>"self"}, {"href"=>"http://10.30.1.49:8774/89fc0b9d984d49fba5328766e923958f/servers/82b7e32b-f62b-4106-b499-e0046250229f", "rel"=>"bookmark"}], "OS-DCF:diskConfig"=>"MANUAL"}}

The code I am using to iterate over the top is:

server_table = Text::Table.new do | t |
      t.head = ['Server ID', 'Server URL', 'Admin Password']
   end
response = JSON.parse(r)

response['server'].each do | serv_info |
  server_table.rows << [["#{serv_info['id']}", "#{serv_info['links'][0]['href']}", "#{serv_info['adminPass']}"]]
end

puts server_table

I am getting the error:

/lib/get_token.rb:166:in `[]': can't convert String into Integer (TypeError)
    from ./lib/get_token.rb:166:in `create_server'
    from ./lib/get_token.rb:165:in `each'
    from ./lib/get_token.rb:165:in `create_server'

If I individually use puts to print out each command they work fine, but the iteration does not. The commands that pull the correct info are:

puts response['server']['links'][0]['href']
puts response['server']['id']
puts response['server']['adminPass']

All 3 of those work, but if I try and iterate over them I get the string error. I know it has something to do with .each returning an Array of hashes but I do not fully understand why the PUTS command is working without issue in the script and also in IRB.

Any thoughts?

2
  • Instead of using puts, try using pp, which will output a formatted version of the data. It's a temporary way to help visualize what your data structure really is. puts can gloss over the nesting by adding an extra line-feed that you don't really pay attention to. Commented Jan 22, 2013 at 23:37
  • Thats good to know, especially since I am new to this :) Thanks man! Commented Jan 23, 2013 at 2:58

3 Answers 3

1

Each serv_info is a pair of a map represented as an array of 2 elements. Therefore everything after << in your code is just wrong.

The secret to avoid such mistakes is to stop trying to obfuscate your own code.

server_table.rows should contain all possible triples of server ID, link and a password.

response = # { "server" => ...}
server = response['server']
server_id = server['id']
link_infos = server['links']
admin_pass = server['adminPass']

link_infos.each do |link_info|
  link = link_info['href']
  server_table.rows << [server_id, link, admin_pass]
end

Update

We can easily use this code to process multiple servers

response = # [ {"server" => ...}, ...]
response.each do |server|
   ... # above code snippet goes here 
       # or you may extract it into a method and call it here
end

Also I want to mention that irb is really great for dealing with this kind of problems. It is a command line Ruby interpreter and it's great for prototyping. It prints out result of each statement you type and has an autocompletion to help you find required classes/methods. Instead of waiting several hours to get an SO answer to simple question you will get it using irb in a couple of minutes.

Sign up to request clarification or add additional context in comments.

5 Comments

hoha, thank you. I am new to ruby, only two weeks in so I really appreciate the answer. I was trying to compact the code I guess, but I see where that would get me into serious trouble in the future. You rock!
Next coding question and I want to see if I get this right. If I get a JSON response that I parse out that has multiple ['server'] entries (creation of multiple server) would I iterate over your code using pastebin.com/MP0RJy2K
@hoha - think I forgot to add this for a notification
There is a mistake in you snippet, in json_response['server'].each you have an array json_resonse and arrays can not be accessed with a string keys (like "server") - you will get an error. See the updated post.
@hoha - so I went through the code this morning and was not able to get it to work, however you did lead me to think about the arrays. It turns out that when I run a response.each | res | it converts response into a 2 position array. response[0] being "server" and response[1] being the hash table. I was able to fix it by doing this: pastebin.com/WBBQCU58 This is tested and working as expected.
0

Perhaps you mean just

serv_info = response['server']
server_table.rows << [["#{serv_info['id']}", "#{serv_info['links'][0]['href']}",      "#{serv_info['adminPass']}"]]

Since response['server'] is a hash not an array.

Comments

0

Instead of using:

server_table.rows << [["#{serv_info['id']}", "#{serv_info['links'][0]['href']}", "#{serv_info['adminPass']}"]]

Try:

server_table.rows += [["#{serv_info['id']}", "#{serv_info['links'][0]['href']}", "#{serv_info['adminPass']}"]]

Or:

server_table.rows << ["#{serv_info['id']}", "#{serv_info['links'][0]['href']}", "#{serv_info['adminPass']}"]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.