Recently I’ve found out some mentions to the “–sandbox” parameter to the “rails console” command.
And I found the idea interesting, but since I'm using Sequel instead
of ActiveRecord I guessed this wouldn’t work for me.
But after talking about this subject in the Sequel mailing list,
Jeremy Evans has brought to my attention that there are some issues with the current approach taken by ActiveRecord.
In case you're curious about the full thread:
https://groups.google.com/forum/?fromgroups#!msg/sequel-talk/VjfJcTD6s3w/Lbrc2RqVuu8J
Here is how sandbox is handled by ActiveRecord:
activerecord/lib/active_record/railties/console_sandbox.rb:
ActiveRecord::Base.connection.increment_open_transactions
ActiveRecord::Base.connection.begin_db_transaction
at_exit do
ActiveRecord::Base.connection.rollback_db_transaction
ActiveRecord::Base.connection.decrement_open_transactions
end
This only handles the default database as noticed by Jeremy. If
you have models relying on different databases, only the default one will be sandboxed.
Additionally, there is another design issue. For example, Sequel
was designed in a way that it won’t allow users to directly manipulate connections and control where to start and end transactions. So it only provides a block-based approach:
Here is how this would be implemented in Sequel (assuming a decent
database like PostgreSQL that supports savepoints - if that is not the case, just remove the :savepoint option):
DB.transaction(savepoint: true, rollback: :always) do
# sandboxed database access here:
u = User[1]
u.name = 'Changed'
u.save_changes
end
I have a similar issue with the design of RSpec lack of an
around(:all) filter similar to around(:each) that won’t allow me to use savepoints to restore the database state when creating common data in a before(:all) section of some contexts.
Sequel does support an "after_connect" hook so that it could be
used to make sure the connection is inside a transaction when it is created. Maybe ActiveRecord could provide something similar and use it instead for dealing with a sandboxed application.
Another issue with the current approach is that if you change some
database data inside a thread, I guess it would spawn a new connection that wouldn’t be sandboxed. Is that right?
Any thoughts about this?
Cheers,
Rodrigo.