2011-12-14 8 views
9

¿Es posible configurar una aplicación Rails de manera que todas las acciones del controlador se envuelvan automáticamente con una transacción, que se retrotrae automáticamente en caso de excepciones no resueltas?Ajustar todas las acciones del controlador en transacciones en Rails

Estoy trabajando en una aplicación Rails 3, actualmente por una acción bastante complicada que hace numerosos cambios en la base de datos. ¡Y me he estado equivocando muchas veces! Después de un tiempo me di cuenta de que mi código no funcionaba porque había terminado con datos inconsistentes en la base de datos.

Puedo envolver esto fácilmente con una transacción (¡es una instancia clara donde se necesita!). Sin embargo, me hizo pensar que, al menos en el desarrollo, sería útil aplicar esta idea en cada acción del controlador.

Suponiendo que es posible, ¿hay algún inconveniente en esto?

Respuesta

5

¿Se puede hacer? probablemente. ¿Debería hacerse? probablemente no, de lo contrario esto sería parte de los rieles, o ya habría una gran joya para esto.

Si tiene acciones de controlador complejas particulares que realizan mucha actividad de db, y desea que estén en una transacción, mi consejo es que esta lógica de negocios y persistencia se conviertan en un método modelo y coloque allí su transacción. Esto también le da más control para los casos en que no siempre quiera que esto suceda.

Si realmente, realmente quiere hacer esto de todos modos, yo apostaría que podría hacerlo con el middleware Rack, como esto (no probado) una 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

Gracias. Voy a pensar si esta es una buena idea. Supongo que el problema es que cualquier transacción que use dentro de la aplicación realmente se incluirá en la transacción externa. Sin embargo, por alguna razón al ver eso, me dio la idea de cómo hacerlo. ¡Publicaré con mi solución para que el código sea más fácil de leer! – asc99c

16

Para información, lo hice con un around_filter en mi controlador de aplicación:

around_filter :wrap_in_transaction 

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

Esto se deshace la transacción sobre cualquier excepción no controlada, y re-plantea la excepción.

+0

Me gusta esta idea, pero ¿cómo puedo acceder a las devoluciones de llamada after_commit y after_rollback con esto? – nexar

+1

Sugiero que agregue un rand de reposo antes de cederlo de nuevo; esto puede explotar su máquina si tiene muchas transacciones simultáneas. – fotanus

Cuestiones relacionadas