ruby-on-rails - ActiveRecord 异常未获救

标签 ruby-on-rails activerecord exception rescue

我有以下代码块:

unless User.exist?(...)
  begin
    user = User.new(...)
    # Set more attributes of user
    user.save!
  rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique => e
    # Check if that user was created in the meantime
    user = User.exists?(...)
    raise e if user.nil?
  end
end

原因是,正如您可能猜到的那样,多个进程可能会同时调用此方法来创建用户(如果它尚不存在),因此当第一个进程进入 block 并开始初始化一个用户时,新用户,设置属性并最后调用保存!,用户可能已经创建了。 在这种情况下,我想再次检查用户是否存在,并且仅在仍然不存在时引发异常(=如果同时没有其他进程创建它)。

问题是,保存时会定期引发 ActiveRecord::RecordInvalid 异常!并且没有从救援区获救。 有什么想法吗?

编辑:

好吧,这很奇怪。我肯定错过了什么。我根据 Simone 的提示重构了代码,如下所示:

unless User.find_by_email(...).present?
  # Here we know the user does not exist yet
  user = User.new(...)
  # Set more attributes of user
  unless user.save
    # User could not be saved for some reason, maybe created by another request?
    raise StandardError, "Could not create user for order #{self.id}." unless User.exists?(:email => ...)
  end
end

现在我遇到了以下异常:

ActiveRecord::RecordNotUnique: Mysql::DupEntry: Duplicate entry 'foo@bar.com' for key 'index_users_on_email': INSERT INTO `users` ...

抛出到“unless user.save”的行中。 怎么可能? Rails 认为可以创建用户,因为电子邮件是唯一的,但 Mysql 唯一索引会阻止插入?这有多大可能?又该如何避免呢?

最佳答案

在这种情况下,您可能希望使用迁移在用户表键上创建唯一索引,这样数据库就会引发错误。

此外,不要忘记在用户模型中添加 validates_uniqueness_of 验证。

验证并不总是可以防止重复数据(两个并发请求在同一毫秒写入的可能性确实很小)。 如果您将 validates_uniqueness_of 与索引结合使用,则不需要所有这些代码。

unless User.exist?(...)
  begin
    user = User.new(...)
    # Set more attributes of user
    user.save!
  rescue ActiveRecord::RecordInvalid, ActiveRecord::RecordNotUnique => e
    # Check if that user was created in the meantime
    user = User.exists?(...)
    raise e if user.nil?
  end
end

变成了

user = User.new(...)
# Set more attributes of user
if user.save
  # saved
else
  # user.errors will return
  # the list of errors
end

关于ruby-on-rails - ActiveRecord 异常未获救,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4617440/

相关文章:

javascript - 传单 geojson 不会显示标记

ruby-on-rails - Rails 允许用户设置默认值

javascript - 如何检测图像加载失败,如果失败,尝试重新加载直到成功?

ruby-on-rails - 何时在连接表上设置没有主键的表

java - 如何在 try-with-resource 语句中捕获 close 方法抛出的异常

ruby-on-rails - 在 Rails 中使用 capybara 单击一个特定按钮

ruby-on-rails - Kaminari 在哪里计算它的页面 url 链接?

ruby-on-rails - Rails 复杂表单使用关联一次编辑多个记录

php - 拉维尔 5.1 : Class html does not exist

node.js - uncaughtException无法捕获引发的错误