Mam sytuację, w której chciałbym, aby metoda działała w ramach transakcji, ale tylko wtedy, gdy transakcja jeszcze się nie rozpoczęła. Oto zmyślony przykład destylować co mówię:Zapewnienie transakcji w ramach metody z ActiveRecord
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
Zasadniczo nie chcę ich do działania jako transakcje zagnieżdżone. Chcę, aby metody .create_multiple
tylko rozpoczynały transakcje, jeśli nie zostały jeszcze wywołane w ramach transakcji, na przykład przez ConductBusinessLogic#process!
. Jeśli metody modelu są wywoływane osobno, powinny rozpocząć własną transakcję, ale jeśli są już wywoływane w ramach transakcji, np. Przez ConductBusinessLogic#process!
, nie powinny zagnieżdżać pod-transakcji.
Nie znam sposobu, w jaki Rails dostarcza to po wyjęciu z pudełka. Jeśli powyższy kod zostanie uruchomiony bez zmian, a wycofanie zostanie wywołane przez jedną z metod modelu, cała transakcja będzie nadal wykonywana, ponieważ transakcja podrzędna połknie wyjątek ActiveRecord::Rollback
. Jeśli użyję opcji requires_new
w przypadku pod-transakcji, punkty zapalne zostaną użyte do symulacji transakcji zagnieżdżonych i tylko ta pod-transakcja zostanie faktycznie wycofana. Zachowanie, które chciałbym osiągnąć, byłoby czymś w rodzaju efektu ActiveRecord::Base.ensure_transaction
, tak że nowa transakcja jest uruchamiana tylko wtedy, gdy nie ma już transakcji zewnętrznej, tak że każda transakcja podrzędna może wywołać wycofanie całej transakcji zewnętrznej. Pozwoliłoby to, aby te metody były transakcyjne same, ale odroczyły transakcję nadrzędną, jeśli taka istnieje.
Czy istnieje wbudowany sposób osiągnięcia tego zachowania, a jeśli nie, czy istnieje klejnot lub łata, które zadziałają?
Co o [transaction_open] (http: //api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/DatabaseStatements.html#method-i-transaction_open-3F)? –