如何确定记录是在 after_save 中创建还是更新

新唱片?函数确定记录是否已被保存。但是在 after_save钩子上总是错误的。是否有一种方法可以确定该记录是新创建的还是更新后的旧记录?

我希望不要使用另一个回调函数(如 before_create)来设置模型中的标志,或者需要对数据库进行另一个查询。

任何建议都不胜感激。

编辑: 需要在 after_save钩子中确定它,对于我的特定用例,没有 updated_atupdated_on时间戳

67839 次浏览

据我所知,这里没有栏杆魔法,你只能自己动手了。您可以使用虚拟属性来清除这些..。

在你的模型课上:

def before_save
@was_a_new_record = new_record?
return true
end


def after_save
if @was_a_new_record
...
end
end

我想用这个来做 after_save的复试。

一个更简单的解决方案是使用 id_changed?(因为它在 update上不会改变) ,如果存在时间戳列,甚至使用 created_at_changed?

更新: 正如@mitsy 指出的,如果在回调之外需要这个检查,那么使用 id_previously_changed?

有一个 after_create回调函数,只有当记录是新记录 在它被拯救之后时才会调用该函数。如果这是已更改和保存的现有记录,则还有一个 after_update回调。在这两种情况下,在调用 after_createafter_update之后,都会调用 after_save回调函数。

如果在保存新记录后需要发生某些事情,请使用 after_create

更多信息请点击: http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

还有一个选择,对于那些 updated_at时间戳的人来说:

if created_at == updated_at
# it's a newly created record
end

因为对象已经被保存,所以您需要查看以前的更改。ID 应该只在创建之后更改。

# true if this is a new record
@object.previous_changes[:id].any?

还有一个实例变量 @new_record_before_save,你可以通过以下操作进行访问:

# true if this is a new record
@object.instance_variable_get(:@new_record_before_save)

Both are pretty ugly, but they would allow you to know whether the object has been newly created. Hope that helps!

Rails 5.1 + 路线:

user = User.new
user.save!
user.saved_change_to_attribute?(:id) # => true

对于 Rails 4(在4.2.11.1上检查) ,changesprevious_changes方法在 after_save内创建对象时的结果是空散列 {}。所以像 id_changed?这样的 attribute_changed?方法不会像预期的那样工作。

但是您可以利用这些知识,并且-知道在更新时至少有1个属性必须在 changes中-检查 changes是否为空。一旦你确认它是空的,你必须在创建对象的过程中:

after_save do
if changes.empty?
# code appropriate for object creation goes here ...
end
end

There is a method called previously_new_record? for exactly this use case.

user = User.new


user.new_record? # => true
user.previously_new_record? # => false


user.save


user.new_record? # => false
user.previously_new_record? # => true

资料来源: https://api.rubyonrails.org/v6.1.4/classes/ActiveRecord/Persistence.html#method-i-previously_new_record-3F

看起来通过调用 saved_change_to_id?提出的解决方案不再有效了。我在 Rails 7上。