我有一份报名表。
当用户注册时,应用程序应该将数据保存在enrollments
表和users
表中。 (我需要这种分离,因为用户的个人资料可以更改,但他为该特定注册输入的数据必须存档。因此,即使稍后用户更改了他的姓氏,我也会在注册表单中获得他的初始信息。)< / p>
所以我在考虑在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
表中回滚并销毁刚刚保存的数据?
答案 0 :(得分:11)
after_create是保存当前模型的事务的一部分。因此,如果您的代码崩溃或者after_create返回false,它应该回滚当前事务并使enrollment
保存无效。
如果你想模拟这个,请将它添加到你的after_create中,看看是否一切都按预期工作:
raise Exception.new("CRASH")
答案 1 :(得分:9)
从false
返回after_create
将无效。
整个回调链包含在一个事务中。如果在回调方法之前返回任何错误或引发异常,则执行链将停止并发出ROLLBACK;回调之后只能通过引发异常来实现。
此外,您必须raise ActiveRecord::Rollback
:
在回调链暂停后,Rails将重新引发任何非ActiveRecord :: Rollback异常。引发除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
答案 2 :(得分:1)
正如@anthonyalberto所提到的,after_create已经是交易的一部分。要定义一个事务,你可以在你的控制器中使用这样的东西:
Enrollment.transaction do
@enrollment.save!
end
这就是你真正需要做的,如果注册保存失败或者用户保存失败,它将回滚你的整个交易。以下是更多信息:http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html
答案 3 :(得分:0)
在Rails 5中,您需要使用throw :abort
来回滚ActiveRecord链。
您可以看到不同版本的Rails中的操作处理列表以及回调之前和之后。为了更好的说明,请查看暂停执行的概念。请点击下面的给定链接。
https://guides.rubyonrails.org/active_record_callbacks.html#halting-execution