是否有更惯用的方法来更新 ActiveRecord 属性哈希值?

Posted

技术标签:

【中文标题】是否有更惯用的方法来更新 ActiveRecord 属性哈希值?【英文标题】:Is there a more idiomatic way to update an ActiveRecord attribute hash value? 【发布时间】:2020-03-11 11:39:05 【问题描述】:

给定一个person ActiveRecord 实例:person.phones #=> home: '00123', office: '+1-45'

是否有更符合 Ruby/Rails 习惯的方式来执行以下操作:

person_phones = person.phones
person_phones[:home] = person_phones[:home].sub('001', '+1')
person.update_column :phones, person_phones

示例数据无关紧要。

我只想sub 一个特定的哈希键值和要保存在数据库中的新哈希。我想知道是否有办法做到这一点,只需调用一次person.phones,而不是多次

【问题讨论】:

惯用语是什么意思?你不能person.update_column(:phones, person.phones[:home].sub('001', '+1'))吗? 嗨塞巴斯蒂安!在您的示例中,sub 将返回一个字符串,并在 update_column 时替换整个哈希。所以你不能这样做:( 对了!真的没看到。您正在使用什么 RDBMS 和版本(如果有)?手机是什么数据类型? mysql。我知道我不应该将哈希值保存到数据库中,但这是一个已经植入的遗留决定 :) person.phones.class #=> ActiveSupport::HashWithIndifferentAccess,如果对你有帮助的话。 【参考方案1】:

在不改变太多行为的情况下:

person.phones[:home].sub!('001', '+1')
person.save

这里有一些重要的区别:

    您可以使用sub! 而不是sub 来修改字符串对象。这意味着所有其他持有对该字符串的引用的变量/对象也将发生变化。 我使用的是save 而不是update_column。这意味着不会跳过回调,所有更改都会保存,而不仅仅是 phones 属性。

根据我的评论,您正在寻找一个与上述没有什么不同的单班轮:

person.tap  |person| person.phones[:home].sub!('001', '+1') .save

【讨论】:

谢谢!正是我想要的【参考方案2】:

您可以在模型上使用before_validation 回调。

像这样:

class Phone < ApplicationRecord

 validates :home, US_PHONE_REGEX

 before_validation :normalize_number

private

 def normalize_number
  home.gsub!(/^001/, '+1')
 end
end

注意:我没有测试过这段代码,它只是为了展示一种方法。

如果您还希望标准化一个国际号码,请评估使用像 phony 这样的库是否更有意义,或者基于它的 rails lib https://github.com/joost/phony_rails。

编辑 因为评论澄清你只想改变哈希值,就像你可以使用Ruby的方法transform_values!:

phones.transform_values!|v| v.gsub(/^001/, '+1')

【讨论】:

嗨,保罗!示例数据无关紧要。我只想知道这是否可以在一行中完成,而不必多次调用person.phones 谢谢保罗!只有两个小 cmets:1)我只想 sub 一个特定的哈希键,而不是全部。 2) 我希望将更改保存在数据库中。我想知道是否有办法做到这一点,只需调用一次person.phones,而不是多次。再次感谢!

以上是关于是否有更惯用的方法来更新 ActiveRecord 属性哈希值?的主要内容,如果未能解决你的问题,请参考以下文章

是否有更干的方法来创建React文本输入表单元素?

复制 activerecord 记录的最简单方法是啥?

基于先前值更新Map中的值的惯用方法

是否有更短的方法来要求 ruby​​ 中同一目录中的文件?

是否有更简洁的方法来获取错误和 Promise 的结果 [重复]

是否有更简单或单行的方法来获取 DataGridViewComboBoxCell 的选定索引?