Hash collect Ruby23 --> Ruby27 and Rails 5.2 --> Rails 6.1 giving wrong element type nil at 0 (expected array)

260 Views Asked by At

I am upgrading Ruby and Rails version for some code package.

I have the following code block that is giving me error of wrong element type nil at 0 (expected array) .

def some_method(var1)
    address_to_field_mapping = { 'name' => 'name'
      'countryCode' => 'countryCode'
    }
# following line errors:
    fields = Hash[address_to_field_mapping.collect{|k,v| [v, var1[k]] unless var1[k].nil?}]
    return {'fields' => fields}
  end

I am not familiar at all with Ruby/Rails, can someone explain what the highlighted line means , and what is actually causing this error ? fields = Hash[address_to_field_mapping.collect{|k,v| [v, var1[k]] unless var1[k].nil?}]

1

There are 1 best solutions below

0
On

This looks like an insanely overcomplicated way of writing:

def some_method(var1)
  { 'fields' => var1.slice('name', 'countryCode').compact }
end

This returns a hash containing the 'name' and 'countryCode' fields if they are not nil. Or at least it would have been if it wasn't broken.

I'm guessing the person writing it didn't know Ruby (hinted by the unnessicary return) yet was very concerned with job security.

So lets break it down:

address_to_field_mapping.collect{|k,v| [v, var1[k]] unless var1[k].nil?}

Hash#collect is an alias of map and loops across the keys and values of an array and returns an array consisting of the return values of the block. The return value here is an array of pairs ['name', 'bob'] or nil. The latter part being where it goes tits up.

Hash[] is a special hash constructor that takes an array of pairs:

irb(main):001:0> Hash[[[foo: 1], [bar: 2], [baz: 3] ]]
=> {{:foo=>1}=>nil, {:bar=>2}=>nil, {:baz=>3}=>nil}

But if you throw a nil in there it blows up.

irb(main):002:0> Hash[[[foo: 1], [bar: 2], nil ]]
(irb):2:in `[]': wrong element type nil at 2 (expected array) (ArgumentError)  

Which could have been fixed by using .compact to remove the nils:

def some_method(var1)
  address_to_field_mapping = { 'name' => 'name'
      'countryCode' => 'countryCode'
  }
  fields = Hash[address_to_field_mapping.collect{|k,v| [v, var1[k]] unless var1[k].nil?}.compact]
  {'fields' => fields}
end