Reputation: 283
I am trying to 'monkey patch' some code we have deployed without breaking the API consumer, basically I want to find param with a key value pair, with value equaling certain value('\u0000') and set it to nil, here is what I have :
def traverse_param(key, value)
if value.is_a? Hash
value.each do |k, v|
return traverse_param(k, v)
end
end
if value == '\u0000'
value = nil
end
end
In rails 5 I cannot pass nil
to the controller as it will be cast to ''
and I need to pass the nil
in param onto the service doing the work below.
Now since I can have nested params this is why I check if the param value is a Hash
. I worked with this example :
params = {:filters=>{:user=>{:disabled_at=>"\u0000"}, :importan_param=>1}}
params.each { |k, v| traverse_param(k,v) }
I m trying to modify the value in place, but it does not seem to work? The code is entering the right places when I debug, but it's not producing desired outcome. Any ideas?
Upvotes: 3
Views: 2738
Reputation: 12203
So, the problem you're facing is that you're modifying a local variable value
. Were you to pass the entire params hash (or sub-hash) to traverse
, you can then update the values as so:
def traverse(params)
params.each do |k, v|
traverse(v) if v.is_a? Hash
params[k] = nil if v == '\u0000'
end
end
# => {:filters=>{:user=>{:disabled_at=>nil}, :importan_param=>1}}
You can tidy this a little using transform_values
if you're Ruby > 2.4:
def traverse(params)
params.dup.transform_values { |v| v == "\\u0000" ? nil : v.is_a?(Hash) ? traverse(v) : v }
end
traverse(params)
# => {:filters=>{:user=>{:disabled_at=>nil}, :importan_param=>1}}
params
# => {:filters=>{:user=>{:disabled_at=>"\\u0000"}, :importan_param=>1}}
Or, far more readable:
def traverse(params)
params.dup.transform_values do |v|
next traverse(v) if v.is_a?(Hash)
v == "\\u0000" ? nil : v
end
end
Hope that's useful - let me know how you get on or if you have any questions.
Upvotes: 3
Reputation: 121000
You are abusing each
for mapping. Mapping is to be done with map
, each
is for iterating.
def fix(hash)
hash.map do |k, v|
[k, case v
when Hash then fix(v)
when '\u0000' then nil
else v
end]
end.to_h
end
Upvotes: 1