6

メソッドをトランザクション内で動作させたい状況がありますが、トランザクションがまだ開始されていない場合のみです。これは、私が話していることを要約するための不自然な例です。

class ConductBusinessLogic
  def initialize(params)
    @params = params
  end

  def process!
    ActiveRecord::Base.transaction do
      ModelA.create_multiple(params[:model_a])
      ModelB.create_multiple(params[:model_a])
    end
  end
end

class ModelA < ActiveRecord::Base
  def self.create_multiple(params)
    # I'd like the below to be more like "ensure_transaction"
    ActiveRecord::Base.transaction do
      params.each { |p| create(p) }
    end
  end
end

class ModelB < ActiveRecord::Base
  def self.create_multiple(params)
    # Again, a transaction here is only necessary if one has not already been started
    ActiveRecord::Base.transaction do
      params.each { |p| create(p) }
    end
  end
end

基本的に、これらがネストされたトランザクションとして機能することは望ましくありません。.create_multipleなどのトランザクション内でメソッドがまだ呼び出されていない場合にのみ、トランザクションを開始するメソッドが必要ですConductBusinessLogic#process!。モデル メソッドが単独で呼び出される場合は、独自のトランザクションを開始する必要がConductBusinessLogic#process!あります。

Railsがこれをすぐに提供する方法を知りません。上記のコードをそのまま実行し、モデル メソッドの 1 つによってロールバックがトリガーされた場合、サブトランザクションがActiveRecord::Rollback例外を飲み込むため、トランザクション全体が引き続き処理されます。サブトランザクションでオプションを使用するrequires_newと、ネストされたトランザクションをシミュレートするためにセーブポイントが使用され、そのサブトランザクションのみが実際にロールバックされます。私が望む動作はActiveRecord::Base.ensure_transaction、外部トランザクションがまだない場合にのみ新しいトランザクションが開始されるようにすることで、サブトランザクションが外部トランザクション全体のロールバックをトリガーできるようにすることです。これにより、これらのメソッドはそれ自体でトランザクション可能になりますが、親トランザクションがある場合はそれに従います。

この動作を実現する組み込みの方法はありますか?そうでない場合、機能するgemまたはパッチはありますか?

4

1 に答える 1

2

クラスcreate_multiple_without_transactionにメソッドをModelA追加するだけではどうですか? ModelBこれは次のようになります。

class ConductBusinessLogic
  def initialize(params)
    @params = params
  end

  def process!
    ActiveRecord::Base.transaction do
      ModelA.create_multiple_without_transaction(params[:model_a])
      ModelB.create_multiple_without_transaction(params[:model_a])
    end
  end
end

class ModelA < ActiveRecord::Base
  def self.create_multiple(params)
    # I'd like the below to be more like "ensure_transaction"
    ActiveRecord::Base.transaction do
      self.create_multiple_without_transaction(params)
    end
  end

  def self.create_multiple_without_transaction(params)
    params.each { |p| create(p) }
  end
end

その後、レギュラーcreate_multipleは以前と同じように機能しますが、トランザクションが必要ない場合は、単に呼び出すだけですcreate_multiple_without_transaction

于 2014-11-14T15:56:59.237 に答える