18

I would like to have a rake task for truncating all the tables. I have found one on the internet, but it is supposed only for Rails 2 and does not work for Rails 3 (problem is in getting a database connection).

rake db:reset is not an option, because I am using PostgreSQL and it also drops the user. Therefore migration fails. I only want to clear the data.

Do you guys have somehting for me?

lzap
  • 16,417
  • 12
  • 71
  • 108

7 Answers7

36

I've found this via google, and then I got a much simpler solution than the one approved, so here it is: Use the database_cleaner gem. Here're the steps.

In your Gemfile (execute bundle after modifying):

gem 'database_cleaner' # you might want to limit this to the dev and staging group

With that gem in place, the statement DatabaseCleaner.clean_with :truncation will truncate the database. Adding it to a rake task is trivial:

# tasks/db/clean.rake

namespace :db do

  desc "Truncate all existing data"
  task :truncate => "db:load_config" do
    DatabaseCleaner.clean_with :truncation
  end

end

That's it. You can also use the DatabaseCleaner.clean_with :truncation line inside your db/seeds.rb file directly so that you don't forget to truncate the database before seeding.

kikito
  • 51,734
  • 32
  • 149
  • 189
19

So I edited the linked example into this:

namespace :db do
  desc "Truncate all existing data"
  task :truncate => "db:load_config" do
   begin
    config = ActiveRecord::Base.configurations[::Rails.env]
    ActiveRecord::Base.establish_connection
    case config["adapter"]
      when "mysql", "postgresql"
        ActiveRecord::Base.connection.tables.each do |table|
          ActiveRecord::Base.connection.execute("TRUNCATE #{table}")
        end
      when "sqlite", "sqlite3"
        ActiveRecord::Base.connection.tables.each do |table|
          ActiveRecord::Base.connection.execute("DELETE FROM #{table}")
          ActiveRecord::Base.connection.execute("DELETE FROM sqlite_sequence where name='#{table}'")
        end                                                                                                                               
       ActiveRecord::Base.connection.execute("VACUUM")
     end
    end
  end
end

This example is based on Chris Ledet's code bellow (thanks) and works with Rails 3.X.

Thanks for all hints.

lzap
  • 16,417
  • 12
  • 71
  • 108
  • 2
    I've added this to make it work with mysql2 : `ActiveRecord::Base.connection.execute("TRUNCATE #{table}") if table != "schema_migrations"`. And `when "mysql", "mysql2", "postgresql"` Otherwise, Rails wanted to migrate everything over again. – Anthony Alberto Sep 04 '12 at 21:29
  • Ya there definitely needs to be a `unless table == 'schema_migrations'` on those truncate lines. – nzifnab Mar 05 '13 at 22:09
  • This crash when has foreign_keys in the tables – betomoretti May 17 '16 at 14:04
10

According to Chris Ledet answer, this becomes much simpler:

ActiveRecord::Base.connection.tables.each do |table|
    ActiveRecord::Base.connection.execute("TRUNCATE TABLE #{table};")
end
Ivan Navarrete
  • 536
  • 1
  • 5
  • 14
Felsangom
  • 1,522
  • 1
  • 10
  • 12
9

To truncate db in Rails 6

rails db:truncate_all  
Dany Alves
  • 163
  • 5
  • 13
  • And if you need to truncate the tables from within your application code you can use rails 6' ```ActiveRecord::Base.connection.truncate_tables```. See https://github.com/rails/rails/blob/82d7e3e21708dcb21b47198f996cf3ec9f372612/activerecord/lib/active_record/tasks/database_tasks.rb#L218. – Diego P. Steiner Apr 27 '20 at 12:03
  • `ActiveRecord::Base.connection.truncate_tables` didn't work. I had to call `ActiveRecord::Tasks::DatabaseTasks.truncate_all` instead. rails 6.0.2.2 – abaldwin99 May 12 '20 at 21:09
6

You could always migrate to version 0, like so:

rake db:migrate VERSION=0

That way you don't even have to truncate your tables, and you can then migrate again. The only catch is that you need your down migrations to work properly.

This solution does work in rails 3, despite the fact that the versions are timestamp-based.

This solution is as seen here: https://stackoverflow.com/a/1196822/241367

Additionally, you could always run the following, assuming your schema.rb is up to date:

rake db:schema:load

And as @kikito suggests, you can run database_cleaner (it's what cucumber and rspec like to use between tests) like so:

DatabaseCleaner.clean_with :truncation
Community
  • 1
  • 1
thekingoftruth
  • 1,711
  • 1
  • 25
  • 24
  • 1
    I like the idea of using db:schema:load. That is very clean and does exactly what I want which is to reset the database without having to drop and recreate. – Jesse Sanford Feb 05 '16 at 01:20
3

This will get all of the tables in your database, find a model associated with that table and call #destroy_all.

tables = ActiveRecord::Base.connection.tables
tables.each do |tbl|
 # "users" => User
 tbl.classify.constantize.destroy_all
end
Chris Ledet
  • 11,458
  • 7
  • 39
  • 47
  • I'm more interested about the Rake task - how to implement it. The linked example only works with Rails 2.x. I am keeping trying that. – lzap Oct 17 '11 at 09:56
  • Wrong. This example works with Rails 3 and 3.1. Nothing is stopping you from putting it in a rake task. – Chris Ledet Oct 17 '11 at 13:55
  • Sorry but you did not provide information how to make a connection in Rails 3 (in a rake task). Its a big difference in Rails 2 and Rails 3. – lzap Oct 27 '11 at 08:42
  • 2
    I use 3.0.10 and 3.1 on a daily basis and this works. Just put it in a rake task and you'll do fine. If it's because I didn't wrap it in a rake task for you so you can just copy and pase it then oh well, I'm not here to spoon feed. This code works when included in a rake task body or rails runner script. – Chris Ledet Oct 27 '11 at 13:48
2

The answer given by lzap has one specific problem. Rails wants to run all the migrations again. The following code is as suggested by Anthony Alberto and it works. This addition checks with the schema_migrations table

namespace :db do
  desc "Truncate all existing data"
  task :truncate => "db:load_config" do
   begin
    config = ActiveRecord::Base.configurations[::Rails.env]
    ActiveRecord::Base.establish_connection
    case config["adapter"]
      when "mysql", "postgresql"
        ActiveRecord::Base.connection.tables.each do |table|
          ActiveRecord::Base.connection.execute("TRUNCATE #{table}") if table != "schema_migrations"
        end
      when "sqlite", "sqlite3"
        ActiveRecord::Base.connection.tables.each do |table|
          ActiveRecord::Base.connection.execute("DELETE FROM #{table}") if table != "schema_migrations"
          ActiveRecord::Base.connection.execute("DELETE FROM sqlite_sequence where name='#{table}'") if table != "schema_migrations"
        end                                                                                                                               
       ActiveRecord::Base.connection.execute("VACUUM")
     end
    end
  end
end