【问题标题】:Create nested records on parent creation在父创建时创建嵌套记录
【发布时间】:2013-11-22 21:16:58
【问题描述】:
我有一个连接用户模型和报告模型的用户报告模型。 (有很多通过关联)。
我有另一个属于 UserReport 的名为 Comment 的模型。 (有很多联想)
创建报告时,我需要为所有用户创建一个带有一个默认评论的 UserReport。
我的问题是,如果任何一个子记录无法保存,如何以一种回滚报告创建的方式执行此操作。
我的目标是确保数据库不会停留在一致性状态。
有什么建议吗?
【问题讨论】:
标签:
ruby-on-rails
activerecord
【解决方案1】:
你想要一种叫做交易的东西。代码看起来像
begin
Report.transaction do
# create report like Report.create! or something
# create comments like Comment.create! or something
end
rescue
# there was an error
end
在事务内部,如果抛出错误,数据库将恢复到整个事务开始之前的状态。在救援中,您可以处理引发的任何错误。
【解决方案2】:
当您save 一个模型时,整个过程都包含在一个事务中,如果保存失败(由于验证、回调等),该事务将回滚。因此,如果您首先在内存中构建整个对象树,然后尝试save 报告,那么如果出现任何故障,您的任何对象都不会被保存。
以下是您可以如何执行此操作的示例:
# in report.rb
class Report < ActiveRecord::Base
validates_associated :user_reports
end
# in user_report.rb
class UserReport < ActiveRecord::Base
validates_associated :comments
end
# in your controller or wherever you're doing this
report = Report.new
User.pluck(:id).each{ |user_id| report.user_reports.build(user_id: user_id) }
report.user_reports.each{ |user_report| user_report.comments.build }
report.save # will always save either everything or nothing, no inconsistencies
注意使用#new 和#build 以避免在最后一行之前提交任何内容。模型中的validates_associated 行会导致子对象上的任何验证错误传播到父对象,即使父对象本身通过验证也无法保存。