I have a special case Model which must not become part of an outer transaction:
Outer.Transaction do
...
Inner.create(:blah)
...
end
How do I stop Inner becoming part of the transaction, assuming Inner should know nothing about which specific transaction it is getting pulled into?
For example, creating an inner transaction is a no go, because that too will become part of the outer transaction.
I want to do this because the inner model needs to write immediately and not wait for the outer transaction to commit.
I’m curious as to what would require such a construct!
I think you’re going to struggle to do it without a bit of hackery as you’ve described. For example, you could, in mysql, set the table storage type for
Innerto one that doesn’t support transactions (MyIsam eg) whilst keeping other classes’ tables storage with something that does support transactions (YUK!).If you can, you’d almost certainly be better off delaying the
Inner.createuntil after the transaction. You can use begin with ensure to make sure that the create always happens. Something like:This would become more complicated if the rest of your block depends on the created
Innerinstance. You could probably create the instance in the block and setcreated_innerto false at the end of the block so that, if the code runs without exception it will have been created in the transaction and you won’t create again in the ensure.If you want to do it in the general case you could define a class method on
Innerto execute a block but always create anInnerobject. You’d need to add anafter_createtoInnertoo. You would rely on theInner.createcall in the block to create it when the transaction succeeds but if it is rolled back then you’d need to create it afterwards. For example:You’d then call it like:
HOWEVER, there’s plenty of downsides to this approach and I’m not sure I’d advocate it. It is complicated. It won’t work if ActiveRecord::Rollback is raised as that exception won’t bubble out of the
Outer.transactionbut will cause theInnerinstance not to be created. It won’t work properly when two or more calls are nested. And finally I haven’t tested it thoroughly – use with caution!