Reputation: 55
I have a UserReport model that connects a User model and a Report model. (has many through association).
I have another model called Comment which belongs to UserReport. (has many association) When a report is created I need to create a UserReport for all users with one default comment.
My question is how to do that in a way that will rollback the report creation if any one of the child records fail to save.
My goal is to ensure that the DB will not stay in in-consisted state.
Any suggestions?
Upvotes: 0
Views: 98
Reputation: 2232
When you save
a model, the entire process is wrapped in a transaction that will be rolled back if the save fails (due to validations, callbacks, etc). So if you build your whole object tree in memory first, then attempt to save
the report, none of your objects will be saved if there are any failures.
Here's an example of how you might do this:
# 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
Note the use of #new
and #build
to avoid committing anything until the final line. The validates_associated
lines in the models cause any validation errors on the child objects to propagate to the parent object, preventing it from saving even if the parent object itself passes validation.
Upvotes: 0
Reputation: 5182
You want something called a transaction. The code would look something like
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
Inside the transaction, if an error is thrown the database is reverted to what it was before the entire transaction was begun. In the rescue, you can handle any errors that were thrown.
Upvotes: 2