是否有更惯用的方法来更新 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 属性哈希值?的主要内容,如果未能解决你的问题,请参考以下文章