在 ruby 中自动投射 JSON 编码数据

Automatically cast JSON coded data in ruby

我的挑战是,在数据库中,JSON 代码存储不整齐。

{'isr_comment':'Test Comment',
'isr_depression_1': '1',
'isr_depression_2': '1'
'isr_depression_3': '1'
'isr_tested': 'true'
}

你看,所有值都定义为字符串,但有些值应该是整数。最好在数据库中已有干净的数据,但我无法控制数据的输入方式。但是我的模型看起来像这样。

class SessionPart < ApplicationRecord
...
  serialize :answers, JSON
...
end

反序列化完成后,我也得到了字符串。

@data=
  {"isr_Comment"=>"Test Comment",
   "isr_depression_1"=>"1",
   "isr_depression_2"=>"1",
   "isr_depression_3"=>"1",
   "isr_tested" => "true"}

但是我需要对这些数据进行一些计算,所以我需要具有有意义类型的所有可能值。

@data=
  {"isr_Comment"=>"Test Comment",
   "isr_depression_1"=>1,
   "isr_depression_2"=>1,
   "isr_depression_3"=>1,
   "isr_tested" => true}

有没有办法自动投射这样的数据?

您可以将自定义序列化程序传递给 serialize 函数。该自定义序列化程序将使用 JSON 作为源序列化程序并根据您的要求更新值。

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

建议的 CustomSerializer 似乎做得很好,谢谢。我做了一些小调整,以便能够嵌套哈希。

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