为什么这段代码不能以事务方式运行?

发布于 2024-11-28 00:33:05 字数 337 浏览 2 评论 0原文

我想销毁与特定用户有关的所有问题。但有些问题受到保护,可以防止自身被破坏并引发异常。

我希望以下代码能够销毁所有问题或不销毁任何问题,但事实并非如此 - 如果其中存在受保护的问题,它不会回滚之前的销毁操作 - 这是为什么?

class User < ActiveRecord::Base
 ...

  Questions.transaction do
    # protected questions will raise a runtime exception
    Questions.destroy_all(:user_id => self.id)
  end
end

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

戏剧牡丹亭 2024-12-05 00:33:05

Grrr,刚刚意识到我以前遇到过这个问题,并且在弄清楚之前浪费了很多时间。

问题是测试是在 RSpec 中完成的,RSpec 本身使用事务并因此从代码中删除事务功能(注意任何从 RSpec 团队阅读此内容的人 - 在解析包含事务的代码时出现警告会很棒 -蒂!)。

为了使事务在 RSpec 中工作,将其包装在以下代码中

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

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文