24

The full error is

ActiveRecord::StatementInvalid: Mysql2::Error: SAVEPOINT active_record_1 does not exist: ROLLBACK TO SAVEPOINT active_record_1

I am writing a unit test and getting this error whenever I try to create a new ActiveRecord object -- but only after a certain point. This occurs after these lines:

ActiveRecord::Base.connection.execute "DROP TABLE IF EXISTS foo"
ActiveRecord::Base.connection.execute "CREATE TABLE foo (id INTEGER PRIMARY KEY)"

(The table 'foo' will be populated with data if my test succeeds)

Before the above lines, I can write something like

User.create(email => 'foo@bar.com')

and everything works fine. However, if I try writing the above line after my call to ActiveRecord::Base.connection.execute, then I get this SAVEPOINT error described above. I've also tried putting my execute statements within a transaction, but that didn't help. I'm stumped.

FYI - I'm using Rails 3.2.8

illusionist
  • 7,996
  • 1
  • 46
  • 63
Duke Silver
  • 1,307
  • 1
  • 13
  • 20

6 Answers6

26

You are using Mysql DDE statements (create/drop/truncate table) which will result in an implicit commit.

Because of the implicit commit, all savepoints of the current transaction are deleted (Refer to above documentation).

To get around this, you can turn off transactions and use DatabaseCleaner (truncation mode).

Community
  • 1
  • 1
awaage
  • 2,429
  • 1
  • 15
  • 15
6

To solve this issue..

config.use_transactional_fixtures = false

vel pradeep.MS
  • 544
  • 5
  • 7
  • 1
    This answer worked for me. I declared `self.use_transactional_fixtures = false` in a subclass of `ActiveSupport::TestCase`. – Masato Ikeda Jan 09 '19 at 04:40
3

You can use "TEMPORARY" when you create/drop tables.

http://dev.mysql.com/doc/refman/5.1/en/implicit-commit.html ALTER TABLE, CREATE TABLE, and DROP TABLE do not commit a transaction if the TEMPORARY keyword is used. (This does not apply to other operations on temporary tables such as CREATE INDEX, which do cause a commit.) However, although no implicit commit occurs, neither can the statement be rolled back. Therefore, use of such statements will violate transaction atomicity: For example, if you use CREATE TEMPORARY TABLE and then roll back the transaction, the table remains in existence.

cheesecow
  • 31
  • 2
2

Just to clarify. You can isolate tests that trigger MySql DDE statements into their own file and then cram config.use_transactional_fixtures = false in that file. This way all your other tests not going to be affected. Now you are responsible for cleanup in that isolated test file.

Grocery
  • 2,114
  • 14
  • 25
0

I found the following links that helped me:

Badea Sorin
  • 174
  • 1
  • 15
0

First ensure that you have the DatabaseCleaner gem installed which will allow you to pick the DB cleaning strategy. The error we are receiving means it will be best to use the truncation strategy.

# file: Gemfile

group :test do
  gem ‘database_cleaner’
end

Add a DatabaseCleaner config to features directory(see below).

#file: features/support/database_cleaner.rb

begin
  require 'database_cleaner'
  require 'database_cleaner/cucumber'

  DatabaseCleaner.strategy = :truncation
rescue NameError
  raise "You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it."
end

Around do |scenario, block|
  DatabaseCleaner.cleaning(&block)
end
Jones Agyemang
  • 929
  • 13
  • 14