Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/variables/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 处理事务内部的唯一约束异常_Ruby On Rails_Ruby_Postgresql - Fatal编程技术网

Ruby on rails 处理事务内部的唯一约束异常

Ruby on rails 处理事务内部的唯一约束异常,ruby-on-rails,ruby,postgresql,Ruby On Rails,Ruby,Postgresql,我有两个Rails模型/表,希望作为事务的一部分插入 例如,以下是我的大致表格: 职位:id 注释:id、帖子id、注释文本、用户id 注释者:id、post_id、用户id、post_id上的唯一约束, 用户id 现在我试着大致相当于: ActiveRecord::Base.transaction do Comment.create!(post: post, user: user, comment_text: '...') begin Commenters.find_or_c

我有两个Rails模型/表,希望作为事务的一部分插入

例如,以下是我的大致表格:

职位:id 注释:id、帖子id、注释文本、用户id 注释者:id、post_id、用户id、post_id上的唯一约束, 用户id 现在我试着大致相当于:

ActiveRecord::Base.transaction do
  Comment.create!(post: post, user: user, comment_text: '...')

  begin
    Commenters.find_or_create_by!(post: post, user: user)
  rescue PG::UniqueViolation
  end
end
这在99.9%的时间内有效,但有时两个并发注释会触发PG::UniqueViolation

尽管我正在捕获并抑制PG::UniqueViolation,但由于以下原因,整个事务失败:

错误:当前事务中止,在事务块结束之前忽略命令

我意识到我已经可以通过加入Post和Comment表来实现这一点,但这只是一个简化的示例


有没有更简单的方法来确保两个插入都作为事务的一部分发生,同时仍然忽略唯一的冲突,因为我们可以假设记录已经存在?

您应该在模型中正确设置关联,以便rails为您进行验证。然后,您可以简单地拯救可能的ActiveRecord::RecordInvalid,消息验证失败:属性已被采用

如果您想了解更多关于唯一性有效性的信息,这应该很方便:

对我来说,你的评论者模型看起来并没有必要。它只是由派生的信息组成,这些信息也可以直接从Comments模型中提取。在那里,您已经存储了post_id和user_id,因此可以完全删除Commenter类。然后注意通过示例设置验证创建时的注释

class Comment
 belongs_to :post
 belongs_to :user
 validates :user_id, uniqueness: {scope: :post_id}
end
但这样你就只允许用户评论一次

我建议您放弃唯一性约束,通过在注释模型上进行不同的选择来构造存储在Commenter中的信息


PS:rails中的模型是用大写和单数编写的,而表是用小写和复数的符号引用的。

事务内部引发的异常有两个作用:

回滚事务,以便在事务内所做的任何更改都不会保留在数据库中。 异常在事务块之外传播。 因此,您可以将异常处理程序移到事务调用之外:


如果您想要更安全,您可以包含一个计数器,以便只重试几次。

如前所述,这不是实际代码,只是一个类似的示例。我认为Rails验证在这里没有帮助,因为由于并发性,仍然可能引发异常:您可能希望更仔细地阅读链接到的指南,尤其是您必须在数据库中的该列上创建唯一索引。唯一性验证永远不够。是的,这正是它的设置方式。唯一索引/约束是问题中提到的由于并发请求而导致PG:UniqueViolation的原因。
begin
  ActiveRecord::Base.transaction do
    Comment.create!(post: post, user: user, comment_text: '...')
    Commenters.find_or_create_by!(post: post, user: user)
  end
rescue PG::UniqueViolation
  retry
end