I've got some jsonb in a database and I want to write to an attribute dynamically, I know the path to the attribute but it could be any depth and any attribute name.
I know the path to the attribute, however the only way I've found of writing this dynamiaclly is with eval()
.
eval("self.some_json_column['an_array'][10]['a_different_array'][5]['color'] = 'blue'")
self.save
So I know the depth and the array index, but it could be any depth or index. I can build the string and pass it into eval()
However I know that eval()
is a last case scenario and was wonderign if it's possible to build the path and write (in this case that color json attribute) dynamically without using eval()
Thanks.
You can reduce your way through the Hash
that is returned by self.some_json_column
*path, target = ['an_array',10,'a_different_array',5,'color']
node = path.reduce(self.some_json_colum, &:[])
node[target] = 'blue' if node
This has no error handling if any part of the path is incorrect
You could also look into dig
depending on ruby version like so
node = self.some_json_column.dig(*path)
node[target] = 'blue' if node
This will return nil
if any part of the path does not match
Example:
h = {
'an_array' => [0,1,2,3,4,5,6,7,8,9,
{'a_different_array' => [1,2,3,4,5, {'color' => 'orange'}]}
]
}
*path,target = ['an_array',10,'a_different_array',5,'color']
h.dig(*path)[target] = 'blue'
h
#=> {"an_array"=>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
# {"a_different_array"=>[0, 1, 2, 3, 4,
# {"color"=>"blue"}
# ]}
# ]}