使用合并!或deep_merge!更新activerecord模型中的哈希值

时间:2017-08-15 15:55:02

标签: ruby-on-rails ruby activerecord merge activeadmin

我的模型中有一个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未合并到现有的空哈希中。

1 个答案:

答案 0 :(得分:2)

reverse_merge!是在Hash中为rails设置默认值的常用方法。

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返回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)