使用合并!或 deep_merge!更新活动记录模型中的散列

Use merge! or deep_merge! to update hash in activerecord model

我的模型中有一个 JSON 列,默认情况下它是一个空散列。

我想检查是否存在特定键,如果不存在,则将空散列与默认散列与键合并。

在我的模型中,我正在检查是否有公用设施(水、煤气或电),如果没有,则插入此默认哈希值:

def default_config
    {:config => {"features" => {"utilities" => {"water" => true, "gas" => true, "electric" => true}}}}
end

这是我检查实用程序密钥是否存在的方式:

  def water 
    has_water? || parent.has_water?
  end 

依次调用这些方法(都在我的模型中):

  def utility(util)
    self[:config].try(:fetch, "features", nil).try(:fetch, "utilities", nil).try(:fetch, "#{util}", nil)
  end

  def has_water?
    utility("water") == true
  end

这是为了能够配置 JSON 列,无论键是否已经存在,我在这里尝试:

 def set_water(boolean) 
    new_val = cleaned_boolean(boolean)
    water ? nil : self[:config].deep_merge!(default_config)
    self[:config]["features"]["utilities"]["water"] = new_val
  end

当我测试这个时,我得到

undefined method `[]=' for nil:NilClass

尝试设置效用值时出错,表明我的 default_config 没有被合并到现有的空哈希中。

reverse_merge! 是在 rails.

中为 Hash 设置默认值的常用方法
self[:config].reverse_merge!(default_config) 

这基本上等于:

default_config.merge!(self[:config]) 

保持 self[:config] 中的所有内容不变,只是合并 default_config 中缺失的键值对。

还有这个三元表达式:

water ? nil : self[:config].deep_merge!(default_config) 

更惯用的写法是(使用Hash#reverse_merge!

self[:config].reverse_merge!(default_config) unless water

并且由于 water returns 一个 boolean 值,它通常被写成一个问题,例如water?(如 has_water?)不确定是否经常使用 water 方法,但我会重构为

def has_water?(include_parent=false)
  utility("water") == true || (include_parent && parent.has_water?)
end

然后调用为:

self[:config].reverse_merge!(default_config) unless has_water?(true)