-1

I have the following code. I don't understand why table['something'] is different from table[:something].

require 'json'
data = '[{"type":"local","db":"all","user":"postgres","addr":null,"method":"ident"},{"type":"local","db":"all","user":"all","addr":null,"method":"ident"},{"type":"host","db":"all","user":"all","addr":"0.0.0.0/0","method":"md5"},{"type":"host","db":"all","user":"all","addr":"::1/128","method":"md5"},{"type":"local","db":"communicator","user":"communicator","addr":" ","method":"trust"}]'
table = JSON.parse(data)
table.each do | auth |
  if (auth['user'])
    print( '\n\n\n' + auth[:user] )
  end
end

And on line with print( '\n\n\n' + auth[:user] ), I'm receiving an error:

TypeError: no implicit conversion of nil into String
        from (irb):88:in `+'

This means that accessing table via :key is different from 'key'. Why? How do I convert table to make it work with :key instead of 'key'?

sawa
  • 165,429
  • 45
  • 277
  • 381
WBAR
  • 4,924
  • 7
  • 47
  • 81

3 Answers3

2

The problem is that {"user":"postgres"} in JSON means:

{"user" => "postgres"}

in Ruby whereas in Ruby it means:

{:user => "postgres"}

Since you have it as JSON, you need to access the value as:

auth["user"]

and not as:

auth[:user]

which is nil since the hash lacks the key :user.

sawa
  • 165,429
  • 45
  • 277
  • 381
1

Because 'key' is a String and :key is a Symbol - those are two different things in Ruby.

It can be somewhat confusing, because :'key', or 'key': will also be a Symbol To make it work, just access Hash fields with a Symbol, like:

if (auth[:user])

To convert String indexed Hash to Symbol indexed Hash, refer to this question:

Best way to convert strings to symbols in hash

Community
  • 1
  • 1
Borsunho
  • 1,127
  • 7
  • 21
1

A Symbol :key is something other than a String 'key', just like a number 3 is something other than a String '3'. To convert a String to a key you can use key.to_sym

About the differance between the two other SO questions have been asked. What's the difference between a string and a symbol in Ruby? See also this article

EDIT A solution to change your keys to symbol if you have no control over the source

require 'json'

data = '[{"type":"local","db":"all","user":"postgres","addr":null,"method":"ident"},{"type":"local","db":"all","user":"all","addr":null,"method":"ident"},{"type":"host","db":"all","user":"all","addr":"0.0.0.0/0","method":"md5"},{"type":"host","db":"all","user":"all","addr":"::1/128","method":"md5"},{"type":"local","db":"communicator","user":"communicator","addr":" ","method":"trust"}]'

table = JSON.parse(data)

p table
# [{"type"=>"local", "db"=>"all", "user"=>"postgres", "addr"=>nil, "method"=>"ident"}, {"type"=>"local", "db"=>"all", "user"=>"all", "addr"=>nil, "method"=>"ident"}, {"type"=>"host", "db"=>"all", "user"=>"all", "addr"=>"0.0.0.0/0", "method"=>"md5"}, {"type"=>"host", "db"=>"all", "user"=>"all", "addr"=>"::1/128", "method"=>"md5"}, {"type"=>"local", "db"=>"communicator", "user"=>"communicator", "addr"=>" ", "method"=>"trust"}]

table.map!{|auth| 
  new_auth = {}
  auth.each{|k, v| new_auth[k.to_sym] = v}
  new_auth
}

p table
# [{:type=>"local", :db=>"all", :user=>"postgres", :addr=>nil, :method=>"ident"}, {:type=>"local", :db=>"all", :user=>"all", :addr=>nil, :method=>"ident"}, {:type=>"host", :db=>"all", :user=>"all", :addr=>"0.0.0.0/0", :method=>"md5"}, {:type=>"host", :db=>"all", :user=>"all", :addr=>"::1/128", :method=>"md5"}, {:type=>"local", :db=>"communicator", :user=>"communicator", :addr=>" ", :method=>"trust"}]
Community
  • 1
  • 1
peter
  • 41,770
  • 5
  • 64
  • 108