rails console --sandbox is only half-baked

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.
  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.

This is intentional. It’s a simple convenience for working with a typical db. Note that it doesn’t sandbox your redis, memcached, or the filesystem, either.

Any thoughts about this?

All good points. But this is all --sandbox was meant to do. We don’t really want to build a general-purpose sandbox that any rollback-able data store can participate in.

Then I guess it would be safer to document this as well when mentioning the sandbox param in the official guides:

http://guides.rubyonrails.org/command_line.html#rails-console

Also, I tried to get a similar result with Sequel but

Rails.application.sandbox? is nil when run inside an initializer file.

I also tried Rails.application.config.after_initialize, but it is

still nil. How can I know if the “–sandbox” parameter was present from the initializer where I set up Sequel?

Thanks in advance,

Rodrigo.

Correct me if I'm wrong, but don't transactional fixtures rollback across all databases in Rails 3? If that's the case, wouldn't it make sense for the sandbox console to reuse that mechanism?

-- donald