After significant troubleshooting, I figured out that I needed to run rake spec once (I can abort with control-c) before I can run rspec directly (e.g. on a sub
The provided solutions all require to load the Rails environment, which is, in most cases, not the desired behaviour due to very large overhead and very low speed. DatabaseCleaner gem is also rather slow, and it adds another dependency to your app.
After months of chagrin and vexation thanks to reasons vide supra, I have finally found the following solution to be exactly what I need. It's nice, simple and fast. In spec_helper.rb:
config.after :all do
ActiveRecord::Base.subclasses.each(&:delete_all)
end
The best part about this is: It will only clear those tables that you have effectively touched (untouched Models will not be loaded and thus not appear in subclasses, also the reason why this doesn't work before tests). Also, it executes after the tests, so the (hopefully) green dots will appear right away.
The only downside to this is that if you have a dirty database before running tests, it will not be cleaned. But I doubt that is a major issue, since the test database is usually not touched from outside tests.
Seeing as this answer has gained some popularity, I wanted to edit it for completeness: if you want to clear all tables, even the ones not touched, you should be able to do something like the "hacks" below.
subclasses methodEvaluate this before calling subclasses:
Dir[Rails.root.join("app", "models", "**", "*.rb")].each(&method(:require))
Note that this method may take some time!
ActiveRecord::Base.connection.tables.keep_if{ |x| x != 'schema_migrations' }
will get you all table names, with those you can do something like:
case ActiveRecord::Base.configurations[Rails.env]["adapter"]
when /^mysql/, /^postgresql/
ActiveRecord::Base.connection.execute("TRUNCATE #{table_name}")
when /^sqlite/
ActiveRecord::Base.connection.execute("DELETE FROM #{table_name}")
ActiveRecord::Base.connection.execute("DELETE FROM sqlite_sequence where name='#{table_name}'")
end