简体   繁体   English

在Rails中的事务中包装所有控制器操作

[英]Wrap all controller actions in transactions in Rails

Is it possible to set up a Rails application such that all controller actions are automatically wrapped with a transaction, that gets automatically rolled back in case of unrescued exceptions? 是否可以设置Rails应用程序,以便所有控制器操作都自动用事务包装,如果出现无法解决的异常,它会自动回滚?

I'm working on a Rails 3 application, currently for a fairly tricky action that makes numerous database changes. 我正在开发一个Rails 3应用程序,目前用于进行大量数据库更改的相当棘手的操作。 And I've been getting it wrong, lots of times! 而且我已经弄错了很多次! After a while I realised my code wasn't working because I'd ended up with inconsistent data in the database. 过了一会儿,我意识到我的代码没有工作,因为我最终得到了数据库中不一致的数据。

I can easily enough wrap this with a transaction (it is a clear instance where one is needed!). 我可以很容易地用事务包装它(这是一个明确的实例,需要一个!)。 However it got me thinking that, at least in development, it would be useful to apply this idea across every controller action. 然而,它让我想到,至少在开发过程中,将这个想法应用于每个控制器动作都是有用的。

Assuming it is possible, is there any downside to this? 假设有可能,这有什么不利之处吗?

For info, I did this with an around_filter in my application controller: 有关信息,我在应用程序控制器中使用around_filter执行此操作:

around_filter :wrap_in_transaction

def wrap_in_transaction
  ActiveRecord::Base.transaction do
    yield
  end
end

This just rolls back the transaction on any unhandled exception, and re-raises the exception. 这只是在任何未处理的异常上回滚事务,并重新引发异常。

Can it be done? 可以吗? probably. 大概。 Should it be done? 它应该完成吗? probably not, otherwise this would be part of rails, or there would already be a great gem for this. 可能不是,否则这将是铁轨的一部分,或者已经有一个伟大的宝石。

If you have particular complex controller actions that are doing lots of db activity, and you want them to be in a transaction, my advice is to get this business logic and persistence into a model method, and put your transaction there. 如果您有特殊的复杂控制器操作正在执行大量的db活动,并且您希望它们处于事务中,我的建议是将此业务逻辑和持久性转换为模型方法,并将您的事务放在那里。 This also gives you more control for the cases where you may not always want this to happen. 这也使您可以更好地控制您可能并不总是希望这种情况发生的情况。

If you really, really want to do this anyway, I would bet you could do it with Rack middleware, like this (untested) one https://gist.github.com/1477287 : 如果你真的,真的想要这样做,我敢打赌你可以用Rack中间件来做,像这样(未经测试)一个https://gist.github.com/1477287

# make this class in lib/transactional_requests.rb, and load it on start
require 'activerecord'

class TransactionalRequests
  def initialize(app)
    @app = app
  end

  def call(env)
    ActiveRecord::Base.transaction do
      @app.call(env)
    end
  end
end

# and in the app config
config.middleware.use "TransactionalRequest"

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM