sandro/specjour

Is there a way to stop the db_scrub task from running?

ozzyaaron opened this issue · 8 comments

I see now that in specjour there is a rails/init.rb that adds an after_initialize block to the rails startup, so now it seems that if you have an initializer that does do some DB setup, whatever task specjour specifies to run will also be run?

I'm using bundler and have :

gem "specjour", :require => nil

And then I have an initializer that does some DB setup. However I cannot figure out how to remove your rails after_initialize block without deleting/renaming the file in the gem.

Any help would be much appreciated.

Thanks
Aaron

I would have thought that :require => nil would not run the rails initializer.

Looks like I'm all wrong, will look at this this weekend.

I thought I had a great solution but it failed. Still looking into it.

Thanks for looking into this!

Yes, I had tried the :require => nil option before but it seems for the time being removing the rails directory stops the init.rb from being included into the rails startup process.

As for other solutions hopefully I will have some time to hack a nicer solution for us today (after work :P).

But us, I mean us here, we use it for about a dozen people. If I come up with anything I'll let you know.

After working on it this afternoon I've yet to find a suitable solution. I want db creation to be automatic for those who need it and to be as simple as no longer requiring the gem for those who don't. It should be as easy as config.gem 'specjour' and config.gem 'specjour', :lib => false. Unfortunately, it's not that easy. Specjour is already required by the time the rails project gets loaded so neither of those configuration statements do anything.

Something like config.gem 'specjour', :lib => 'specjour/db_scrub' may successfully load the scrubber but that means db scrubbing becomes opt-in (breaking backwards-compatibility) instead of opt-out. Additionally, the :lib option is being abused to load an ancillary library instead of the whole gem.

We could use environment variables again:
Somewhere in your rails app you'll do ENV['SPECJOUR_SKIP_DB_SCRUB'] = 'true' to skip the scrubber. Or the PREPARE_DB environment variable could be memoized so you can set that before starting the manager:

PREPARE_DB=false specjour -p project_name.

I don't particularly like this idea.

Maybe there's a configuration option:

# config/environment.rb
Specjour.prepare_db = false

This is cleaner than environment variables but I don't like introducing a configuration object just for one configuration option. Still, this may be the simplest, most unobtrusive idea.

Another idea is to create a rails generator which spits out the db_scrub code as an initializer. This way, we're completely transparent about how we're mucking with your database, it's opt-in and gives users example code that they can modify as needed.

Something to keep in mind is that soon specjour will be moving toward a command-line approach, ditching the rake tasks. When this happens, I envision having a command which prepares the db on all listening workers. So, specjour prepare project_name would essentially run Specjour::DbScrub.scrub on every worker. This is important because sometimes, the databases can get out of sync; especially when everyone decides to write a migration at around the same time. Of course, if you have your own custom db setup, the command won't be able to run.

Maybe a strategy pattern is the best way to encapsulate this stuff:
# default
Specjour.database_preparation { Specjour::DbScrub.scrub }
# custom in your rails app
Specjour.database_preparation { MyCustomPrepartion.prepare }

Then $ specjour prepare could work with custom setups:
#pseudo code
def prepare
workers.each {|w| w.load_rails; w.database_preparation.call}
end

I also ran into this issue. I chose the easy way out by adding the following initializer to <project_root>/config/initializers/specjour_db_scrub.rb:
# Change DB Scrub to call my own rake task
require 'specjour/db_scrub'

module Specjour
  module DbScrub
    def scrub
      Rake::Task["db:test:my_task"].invoke
      # In case you do call db:test:prepare in your task, you will need to following line too:
      ActiveRecord::Base.connection.reconnect!
    end
  end
end

PS: +1 for the Specjour.database_preparation { MyCustomPrepartion.prepare }

Cool. This has been added to the new version. Read about Custom Hooks in 0.3.0 release candidate: http://github.com/sandro/specjour/tree/thor. Before fork is the hook for cleaning the database while the prepare hook is used to create one from scratch and migrate it. Before fork still migrates when necessary.