Rails 3忽略Postgres唯一约束异常

J P*_*ato 9 postgresql activerecord ruby-on-rails ruby-on-rails-3 rails-activerecord

什么是挽救异常并继续处理的正确方法?我有一个具有文件夹和项目的应用程序,通过名为folders_items的连接表具有habtm关系.该表具有唯一约束,确保没有重复的项目/文件夹组合.如果用户尝试多次将项目添加到同一文件夹,我显然不希望添加其他行; 但我也不想停止处理.

当违反唯一约束时,Postgres会自动抛出异常,因此我尝试在控制器中忽略它,如下所示:

rescue PG::Error, :with => :do_nothing

def do_nothing

end
Run Code Online (Sandbox Code Playgroud)

这在单次插入时工作正常.控制器执行渲染,状态代码为200.但是,我有另一种方法在循环中执行批量插入.在该方法中,控制器在遇到第一个重复行时退出循环,这不是我想要的.起初,我认为循环必须包含在正在回滚的事务中,但事实并非如此 - 重复插入之前的所有行.我希望它只是忽略约束异常并移动到下一个项目.如何防止PG :: Error异常中断此操作?

mu *_*ort 14

通常,您的异常处理应该位于错误的最近点,您可以使用异常做一些合理的事情.在你的情况下,你需要你的rescue内部循环,例如:

stuff.each do |h|
  begin
    Model.create(h)
  rescue ActiveRecord::RecordNotUnique => e
    next if(e.message =~ /unique.*constraint.*INDEX_NAME_GOES_HERE/)
    raise
  end
end
Run Code Online (Sandbox Code Playgroud)

几个兴趣点:

  1. 数据库中的约束违规将给您一个ActiveRecord::RecordNotUnique错误而不是底层PG::Error.AFAIK,PG::Error如果你直接与数据库交谈而不是通过ActiveRecord ,你会得到一个.
  2. 替换INDEX_NAME_GOES_HERE为唯一索引的真实名称.
  3. 你只想忽略你所期望的特定约束违规,因此无论是无next if(...)争论的raise(即如果它不是你期望看到的那样,则重新引发异常).