Reputation: 533
My challenge is that in the database, JSON code was untidily stored.
{'isr_comment':'Test Comment',
'isr_depression_1': '1',
'isr_depression_2': '1'
'isr_depression_3': '1'
'isr_tested': 'true'
}
You see, all values are defined as string but some should be integers. It would be the best to have clean data already in the database but I cannot control how the data is entered. However my model looks like this.
class SessionPart < ApplicationRecord
...
serialize :answers, JSON
...
end
As expected after deserialization is done I get strings as well.
@data=
{"isr_Comment"=>"Test Comment",
"isr_depression_1"=>"1",
"isr_depression_2"=>"1",
"isr_depression_3"=>"1",
"isr_tested" => "true"}
But I need to do some calculation with this data so I need all possible values with a meaningful type.
@data=
{"isr_Comment"=>"Test Comment",
"isr_depression_1"=>1,
"isr_depression_2"=>1,
"isr_depression_3"=>1,
"isr_tested" => true}
Is there any way to cast such data automatically?
Upvotes: 0
Views: 65
Reputation: 2424
You can pass your custom serializer to serialize function. That custom serializer would use JSON as source serializer and update the values as per your requirements.
class SessionPart < ApplicationRecord
...
serialize :answers, CustomSerializer #CustomSerializer must write 2 class level function named dump & load for serializing and de-serializing respectively
...
end
class CustomSerializer
def self.load(value)
normalize_hash(JSON.load(value))
end
def self.dump(value)
JSON.dump(value)
end
private
def self.normalize_hash hash
return hash unless hash.is_a? Hash
hash.transform_values {|v| normalize(v)}
end
#change this function as per your requirement, Currently it's handling boolean,integer,float & null rule set
def self.normalize(value)
case (value)
when 'true'
true
when 'false'
false
when 'null','nil'
nil
when /\A-?\d+\z/
value.to_i
when /\A-?\d+\.\d+\z/
value.to_f
else
value.is_a?(Hash) ? normalize_hash(value) : value
end
end
end
Upvotes: 1
Reputation: 533
The suggested CustomSerializer
seems to do its job very well, thanks. I did some small adjustments to be able to nest hashes.
class CustomSerializer
def self.load(value)
normalize_hash(JSON.load(value))
end
def self.dump(value)
JSON.dump(value)
end
private
def self.normalize_hash hash
return hash unless hash.is_a? Hash
hash.transform_values {|v| normalize(v) }
end
#change this function as per your requirement, Currently it's handling boolean,integer,float & null rule set
def self.normalize(value)
case (value)
when 'true'
true
when 'false'
false
when 'null','nil'
nil
when /\A-?\d+\z/
value.to_i
when /\A-?\d+\.\d+\z/
value.to_f
else
value.is_a?(Hash) ? normalize_hash(value) : value
end
end
end
Upvotes: 0