我需要在数据库更新之前和之后比较一些Rails(2.3.11)模型属性值,所以我首先找到我的记录并将现有属性值保存在哈希中,如下所示:
id = params[:id]
work_effort = WorkEffort.find(id)
ancestor_rollup_fields = {
:scheduled_completion_date => work_effort.scheduled_completion_date
}
work_effort.update_attributes(params.except(:controller, :action))
#etcetera
注意我坚持使用符号作为哈希键的“最佳实践”。
然后我有一个方法,如果哈希值和模型属性中的值不匹配,则采用模型和哈希来确定可能采取的其他步骤。为了确定这一点,我尝试在每个循环中获取模型属性值,但我最初得到nil:
def rollup_ancestor_updates(work_effort, ancestor_rollup_fields)
ancestor_rollup_fields.each do |key, value|
model_val = work_effort.attributes[key] #nil
#etcetera
在调试上面的内容中,我注意到将字符串硬编码为键:
work_effort.attribute['scheduled_completion_date']
返回所需的值。那么在我的每个块中我尝试了以下它并且它起作用了:
model_val = work_effort.attributes[key.to_s]
有不同的方法吗?对我来说,仅仅3个月的Ruby / Rails经验,使用符号作为散列键就像规定的最佳实践一样令人困惑,但是必须在符号上调用.to_s才能获得模型属性。有没有其他人经历过这个,解决过这个,也被这个混淆了?提前致谢
答案 0 :(得分:10)
当您在AR实例上调用#attributes
时,返回的哈希值具有字符串键,这就是为什么作为哈希索引的符号在您的情况下不起作用的原因。有一个名为Hash
的{{1}}子类,它自动将符号索引转换为字符串。
在Rails中经常会遇到HashWithIndifferentAccess
个实例。一个完美的例子是您在控制器中访问的params变量和查看代码。
尝试使用HashWithIndifferentAccess
真的,它只是做同样的事情,但它在幕后做。
答案 1 :(得分:5)
您可以使用自己的方法覆盖属性方法。
打开WorkEffort类
class WorkEffort
def attributes
super.symbolize_keys
end
end
然后当你调用work_effort.attributes时,你将在哈希中有符号化的键。
答案 2 :(得分:1)
您所有的Rails模型都可以具有符号化的属性名称:
class ApplicationRecord < ActiveRecord::Base
# ...
class << self
def attribute_names(symbols = false)
return self.attribute_names.map(&:to_sym) if symbols
super()
end
end
end
然后,您可以调用MyModel.attribute_names(symbols = true)
并返回[:id, :my_attribute, :updated_at, :created_at, ...]
,同时仍然允许attribute_names
返回字符串。
请注意,you need the parentheses after super
可以避免原始定义的函数出现参数错误。
答案 3 :(得分:0)
您可能想要使用:stringify_keys!它遍及Rails代码广泛使用。
def rollup_ancestor_updates(work_effort, ancestor_rollup_fields)
ancestor_rollup_fields.stringify_keys!.each do |key, value|
model_val = work_effort.attributes[key]
end
#....
end