7

我有一张报名表。

当用户注册时,应用程序应该将数据保存在enrollments表和users表中。(我需要这种分离,因为用户的个人资料可以更改,但他为该特定注册输入的数据必须存档。所以即使稍后用户更改了他的姓氏,在注册表格中我也会有他的初始信息。)

所以我正在考虑在enrollments表中保存数据然后有一个 after_create 调用,像这样......

class Enrollment < ActiveRecord::Base

  after_create :save_corresponding_user

  def save_corresponding_user
    user = User.new
    user.full_name = self.user_full_name
    user.email = self.user_email
    user.mobile_phone = self.user_mobile_phone
    user.save
  end
end

问题是,如果保存用户因任何原因失败怎么办。如何回滚和销毁enrollments表中刚刚保存的数据?

4

4 回答 4

12

false从那里回来after_create不会做任何事情。

整个回调链被包装在一个事务中。如果任何 before 回调方法完全返回 false 或引发异常,则执行链将停止并发出 ROLLBACK;after 回调只能通过引发异常来实现。

此外,您必须raise ActiveRecord::Rollback

任何不是 ActiveRecord::Rollback 的异常都会在回调链停止后被 Rails 重新引发。引发除 ActiveRecord::Rollback 之外的异常可能会破坏不期望像 save 和 update_attributes 等方法(通常尝试返回 true 或 false)引发异常的代码。

http://guides.rubyonrails.org/active_record_callbacks.html#halting-execution

我做这样的事情:

after_create do
  if condition
    errors.add(:attr, 'Blah blah blah.')
    raise ActiveRecord::Rollback
  end
end

对于 Rails 3: http: //guides.rubyonrails.org/v3.2.13/active_record_validations_callbacks.html#halting-execution

于 2015-11-03T20:33:36.670 回答
11

after_create 是保存当前模型的事务的一部分。因此,如果您的代码崩溃或 after_create 返回 false,它应该回滚当前事务并使enrollment保存无效。

如果您想模拟这一点,请将其添加到您的 after_create 中,看看是否一切都按预期工作:

raise Exception.new("CRASH")
于 2012-07-27T17:29:25.607 回答
1

正如@anthonyalberto 提到的, after_create 已经是交易的一部分。要定义一个事务,你可以在你的控制器中使用这样的东西:

Enrollment.transaction do
  @enrollment.save!
end

这就是您真正需要做的所有事情,如果注册保存失败或用户保存失败,它将回滚您的整个事务。这里有更多信息:http ://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html

于 2012-07-27T18:28:13.737 回答
1

在 rails 5 中,您需要使用throw :abortActiveRecord 链来回滚。

在此处输入图像描述

您可以看到不同版本的 Rails 中的操作处理列表以及之前和之后的回调。为了更好地说明,请查看停止执行的概念。请按照下面给定的链接。

https://guides.rubyonrails.org/active_record_callbacks.html#halting-execution

于 2019-07-29T10:37:09.093 回答