如何确定是否刚刚在after_save中创建或更新了记录

Aar*_*ian 93 activerecord ruby-on-rails activemodel

#new_record?function确定是否已保存记录.但它总是假的after_save.有没有办法确定记录是新创建的记录还是更新的旧记录?

我希望不要使用另一个回调,比如before_create在模型中设置一个标志或者需要另一个查询到db.

任何建议表示赞赏.

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

Zub*_*bin 161

我想用它来after_save回调.

一个更简单的解决方案是使用id_changed?(因为它不会改变update)或者即使created_at_changed?存在时间戳列.

更新:正如@mitsy指出的那样,如果在回调之外需要进行此检查,那么请使用id_previously_changed?.查看文档.

  • 最好用after_update和after_create区分.回调可以共享一个公共方法,该方法接受一个参数来指示它是创建还是更新. (6认同)
  • 通过[ActiveModel :: Dirty](http://api.rubyonrails.org/classes/ActiveModel/Dirty.html) (3认同)
  • 保存记录后,`id_changed?`将为false(至少在钩子之外).在这种情况下,您可以使用`id_previously_changed?` (3认同)
  • 这可能已经改变了.至少在Rails 4中,after_save回调在after_create或after_update回调之后运行(请参阅http://guides.rubyonrails.org/active_record_callbacks.html). (2认同)
  • 检查这些字段都不在`after_save`之外工作. (2认同)
  • 看起来 `id_changed?` 正在被弃用,取而代之的是 `saved_change_to_id?`。使用 `id_changed?` 后,我在控制台中看到了这条消息:“DEPRECATION WARNING: The behavior of `attribute_changed?` 在 after 回调中将在下一个版本的 Rails 中改变。新的返回值将反映调用`save` 返回后的方法(例如,与现在返回的相反)。要保持当前行为,请改用 `saved_change_to_attribute?`。 (2认同)

Jef*_*tte 30

我知道,这里没有铁路魔法,你必须自己做.您可以使用虚拟属性清理它...

在您的模型类中:

def before_save
  @was_a_new_record = new_record?
  return true
end

def after_save
  if @was_a_new_record
    ...
  end
end
Run Code Online (Sandbox Code Playgroud)


col*_*lin 24

另一种选择,对于那些谁有一个updated_at时间戳:

if created_at == updated_at
  # it's a newly created record
end
Run Code Online (Sandbox Code Playgroud)


小智 22

after_create只有在记录保存后,如果记录是新记录,则会调用回调.after_update如果这是一个已更改并保存的现有记录,则还有一个回调可供使用.该after_save回调被称为在这两种情况下,无论是后after_create还是after_update被调用.

after_create如果您在保存新记录后需要执行某些操作,请使用此选项.

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

  • 这实际上可能不是真的。如果您在创建中有关联,则 after_create 将在创建关联之前调用,因此如果您需要确保创建了所有内容,则需要使用 after_save (4认同)

Tom*_*ssi 17

由于对象已经保存,您需要查看以前的更改.ID应仅在创建后更改.

# true if this is a new record
@object.previous_changes[:id].any?
Run Code Online (Sandbox Code Playgroud)

还有一个实例变量@new_record_before_save.您可以通过执行以下操作来访问它:

# true if this is a new record
@object.instance_variable_get(:@new_record_before_save)
Run Code Online (Sandbox Code Playgroud)

两者都非常丑陋,但它们可以让您知道对象是否是新创建的.希望有所帮助!


Tob*_*ias 14

有一种方法previously_new_record?正是针对这种用例而调用的。

user = User.new

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

user.save

user.new_record? # => false
user.previously_new_record? # => true
Run Code Online (Sandbox Code Playgroud)

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

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


Jac*_*cka 8

Rails 5.1+ 方式:

user = User.new
user.save!
user.saved_change_to_attribute?(:id) # => true
Run Code Online (Sandbox Code Playgroud)