Why is this code not behaving transactionally?
I want to destroy all the questions to do with a particular user. Some questions are protected though and may prevent themselves from being destroyed and raise an exception.
I would expect the following code to destroy either all questions or none however it doesn't - if there is a protected question amongst the others it doesn't roll back the previous destroy actions - why开发者_开发问答 is this?
class User < ActiveRecord::Base
...
Questions.transaction do
# protected questions will raise a runtime exception
Questions.destroy_all(:user_id => self.id)
end
end
Grrr, just realised I'd hit this problem before and wasted a load of time then before figuring it out.
The issue is that the test is being done in RSpec which itself uses transactions and removes transactional functionality from the code as a result (n.b. anyone reading this from the RSpec team - it would be great to have a warning when parsing code that contains transactions - ty!).
In order to make the transaction work within RSpec wrap it in the following code:
describe "the set of cases you want to address" do
# make sure this next line is contained within a describe block or it'll affect everything
self.use_transactional_fixtures = false
after(:each) do
# destroy all objects you created (since RSpec won't roll them back for you)
# use delete rather than destroy to force removal
User.delete_all
Question.delete_all
end
it "should not destroy any questions when one fails to be destroyed" do
# assuming one of the questions throws an error on being destroyed
expect{
@user.destroy
}.to change{ Question.all.count }.by(0)
end
end
end
精彩评论