2011-12-14 2 views
9

Czy możliwe jest skonfigurowanie aplikacji Rails tak, że wszystkie akcje kontrolera są automatycznie pakowane w transakcję, która zostaje automatycznie wycofana w przypadku nieuregulowanych wyjątków?Zawijanie wszystkich działań kontrolera w transakcjach w Railsach

Pracuję nad aplikacją Rails 3, obecnie dla dość skomplikowanej akcji, która powoduje liczne zmiany w bazie danych. I robię to źle, wiele razy! Po pewnym czasie zorientowałem się, że mój kod nie działa, ponieważ w bazie danych znalazłem niespójne dane.

Mogę z łatwością zawinąć to za pomocą transakcji (jest to wyraźna instancja, w której jedna jest potrzebna!). Jednak przyszło mi do głowy, że przynajmniej w fazie rozwoju, warto zastosować ten pomysł w każdej akcji kontrolera.

Zakładając, że jest to możliwe, czy jest jakiś minus tego?

Odpowiedz

5

Czy można to zrobić? prawdopodobnie. Czy należy to zrobić? prawdopodobnie nie, w przeciwnym razie byłaby to część torów, lub byłby już dla tego wielki klejnot.

Jeśli masz określone złożone działania kontrolera, które wykonują wiele działań db, i chcesz, aby były one w transakcji, moja rada jest taka, aby uzyskać logikę biznesową i trwałość w metodę modelu i umieścić tam swoją transakcję. Zapewnia to również większą kontrolę w przypadkach, gdy nie zawsze chcesz, aby tak się stało.

Jeśli naprawdę chcesz to zrobić tak, chciałbym postawić można zrobić z Rack middleware, jak to (nietestowanego) jeden 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" 
+0

Dzięki. Zamierzam zastanowić się, czy to dobry pomysł. Chyba problem polega na tym, że wszystkie transakcje, których używam w aplikacji, zostaną po prostu połączone w zewnętrzną transakcję. Jednak z jakiegoś powodu, widząc to, dało mi to pomysł, jak to zrobić. Będę publikować za pomocą mojego rozwiązania, aby kod był łatwiejszy do odczytania! – asc99c

16

Informacje, zrobiłem to z around_filter w moim kontroler aplikacji:

around_filter :wrap_in_transaction 

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

To właśnie wycofuje transakcję w dowolnym nieobsługiwany wyjątek i ponownie pojawia się wyjątek.

+0

Podoba mi się ten pomysł, ale jak uzyskać dostęp do callbacków after_commit i after_rollback przy użyciu tego? – nexar

+1

Sugeruję, aby dodać randek do spania przed ponownym wydaniem - ta rzecz może spowodować eksplozję twojego komputera, jeśli masz wiele równoczesnych transakcji. – fotanus