我在模型上有一个after_save回调,我正在调用previous_changes来查看属性(is_complete)是否发生了变化。即使属性发生更改,previous_changes也会返回空哈希值。
这是回调:
after_save do |record|
puts "********************"
puts record.previous_changes.to_s
puts record.is_complete
puts "********************"
end
以下是我在日志中的内容:
********************
{}
true
********************
********************
{}
false
********************
如果is_complete的值从true更改为false,则它应该在previous_changes哈希中。更新正在通过正常保存完成!而且我没有重新加载这个对象。
--- 更新 ---
当我发布问题时我没有考虑过这个问题,但我的模型使用了awesome_nested_set gem,看来这是重新加载对象或以某种方式干扰after_save回调。当我注释掉acts_as_nested_set时,回调似乎工作正常。
--- 更新2 ---
使用around_save回调修复此问题,该回调首先确定属性是否已更改,然后生成,然后执行在数据库中进行更改后需要执行的操作。工作解决方案如下所示:
around_save do |record, block|
is_complete_changed = true if record.is_complete_changed?
block.call
if is_complete_changed
** do stuff **
end
end
答案 0 :(得分:5)
根据ActiveModel::Dirty源代码
从第274行
def changes_applied # :doc:
@previously_changed = changes
@changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
end
因此,在调用@previously_changed
后,更改将设置为changes_applied
,并且在调用changes_apply
时调用save
,这意味着AFTER DOING PERSISTENT WORK
(行42)
总之,previous_changes
仅在记录实际保存到持久存储(DB)时具有值
所以在你的回调中,你可以使用record.changed_attributes
,而在外面使用previously_changed
,它会正常工作!
答案 1 :(得分:2)
我没有深挖,但从第一眼看到ActiveModel::Dirty
你can see,方法previous_changes
:
def previous_changes
@previously_changed ||= ActiveSupport::HashWithIndifferentAccess.new
end
@previously_changed
未在任何地方定义(except for here,它使用我在下面提到的changes
方法),因此您获得了空(虽然很好并且具有无差别的访问权限:D)哈希一直以来。
您真正想要使用的是changes
方法:
def changes
ActiveSupport::HashWithIndifferentAccess[changed.map { |attr| [attr, attribute_change(attr)] }]
end
它将返回您的预期
#=> {"is_complete"=>[true, false]}