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

时间:2011-02-11 23:30:56

标签: ruby-on-rails activerecord activemodel

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

我希望不使用其他回调(如before_create)在模型中设置标记或要求对数据库进行另一次查询。

任何建议表示赞赏。

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

8 个答案:

答案 0 :(得分:152)

我希望将其用于after_save回调。

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

更新:正如@mitsy指出的那样,如果在回调之外需要进行此检查,则使用id_previously_changed?。见docs

答案 1 :(得分:30)

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

在您的模型类中:

def before_save
  @was_a_new_record = new_record?
  return true
end

def after_save
  if @was_a_new_record
    ...
  end
end

答案 2 :(得分:24)

对于那些的人有updated_at时间戳的另一种选择:

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

答案 3 :(得分:23)

只有当记录是新记录时才会调用after_create回调,保存后会调用。如果这是一个已更改并保存的现有记录,还可以使用after_update回调。在调用after_saveafter_create之后,在两种情况下都会调用after_update回调。

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

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

答案 4 :(得分:16)

由于对象已经保存,您需要查看以前的更改。该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)

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

答案 5 :(得分:5)

采用5.1+轨道:

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

答案 6 :(得分:1)

对于Rails 4(在4.2.11.1中进行了检查),changesprevious_changes方法的结果是{}内部对象创建时的空哈希值after_save。因此,attribute_changed?之类的id_changed?方法无法按预期工作。

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

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

答案 7 :(得分:-1)

即使我知道:id正常情况下也不会改变,但我还是想具体一点,但

(byebug) id_change.first.nil?
true

确定特定的东西总是便宜,而不是发现非常奇怪的意外错误。

如果我希望从不可信的参数中获取true标志,则采用相同的方式

def foo?(flag)
  flag == true
end

这样可以节省大量时间,避免出现奇怪的错误。