抢救ActiveRecord :: RecordNotUnique时遇到的问题

时间:2016-03-29 23:07:32

标签: sql ruby-on-rails ruby postgresql activerecord

我正在尝试构建一个表,该表将充当第三方服务的批量同步队列。

以下方法应该说明一切;但要明确的是,它的目的是将status: :queued的新可更新对象(多态关系)添加到delayed_syncs表。

多态关系+ statusupdatable_idupdatable_typestatus)存在唯一性约束,这会导致队列中已存在可更新对象{{{ 1}}在这里失败并陷入救援区。

我看到的问题是,每当:queued status生成的SELECT被触发时,整个方法都会失败并显示:

  

的ActiveRecord :: StatementInvalid

错误。

我发现的信息表明在失败find_by之后ROLLBACKRELEASE SAVEPOINT,但我不确定如何在此处完成此操作。< / p>

上述方法:

INSERT

2 个答案:

答案 0 :(得分:1)

您可以使用ActiveRecord事务来确保全部或全无更新,而不是依赖逻辑的异常处理。

像这样:

ActiveRecord::Base.transaction do
  DelayedSync.create!(updatable: updatable, status: :queued, action: action)
end

您仍然可以安全地利用rescue来处理日志记录清理。

可以找到有关此详细信息的文档here

答案 1 :(得分:0)

在进一步挖掘之后,我发现问题是由于我如何从after_save回调调用此方法。在关闭交易之前,Rails会调用after_saveafter_destroy个回调。 Postgres无法解决从此回调调用的ActiveRecord::RecordNotUnique错误并尝试执行更多查询,因为它会使整个事务无效。我的解决方案是转换为after_commit回调,它提供与after_saveafter_destroy相同的控件和on: [:create, :destroy]参数,并且有利于在<<>后执行 / strong>交易(无效或无效)已经关闭。

这篇博文有点过时了,但是底部附近的信息非常有用,仍然适用:http://markdaggett.com/blog/2011/12/01/transactions-in-rails/