0

I've created a demo of my program. The demo is used to present the program to the customers. Before each presentation I want to reset the db, and insert certain data, the actions that I have to do are:

rake db:drop
rake db:setup
rake db:seed:demo

But they are not always me to present it and others do not use the console, so I wanted to put in the settings page the ability to reset via a button.

I tried in this way:

module SettingsHelper
require 'rake'
  def reset
        Rake::Task[db:drop].invoke
        Rake::Task[db:setup].invoke
        Rake::Task[db:seeds:demo].invoke
  end
end

I put in the form:

  <%=button_to "Reset", reset, class:"btn red" %>

But I can not drop the database with the active server ... how can I do?

Patrick Barattin
  • 617
  • 6
  • 18

2 Answers2

2

You cannot drop the database while you have an active connection. Instead what you can do is issue a TRUNCATE command which deletes all rows from the table and reset the ID columns.

Incase you want a more fine grained control over exactly which tables are truncated you can add a class method to the model:

class User < ActiveRecord::Base
  self.truncate!
    self.connection.execute(
      "TRUNCATE TABLE #{ self.table_name };"
    )
    self.connection.reset_pk_sequence!(self.table_name)
  end
end 

But lets DRY it into a module so we don't have to repeat it in all the models that should have this behavior:

# app/models/concerns/resetable.rb
module Resetable
  extend ActiveSupport::Concern
  class_methods do
    def truncate!
      self.connection.execute(
        "TRUNCATE TABLE #{ self.table_name };"
      )
      self.connection.reset_pk_sequence!(self.table_name)
    end
  end
end

# app/models/user.rb
class User < ActiveRecord::Base
  include Resetable
  # ...
end 

 # app/models/book.rb
class Book < ActiveRecord::Base
  include Resetable
  # ...
end 
# ...

You can then reset the data for each model by:

def reset_db
  [User, Book, Thing].each { |model| model.truncate! }
  Rails.application.load_seed
end

If you just want to nuke all the tables you can simply do:

ActiveRecord::Base.connection.tables.each do |t|
  conn = ActiveRecord::Base.connection
  conn.execute("TRUNCATE TABLE #{t} CASCADE;")
  conn.reset_pk_sequence!(t)
end
max
  • 96,212
  • 14
  • 104
  • 165
  • `TRUNCATE ... CASCADE` is a Postgres specific way to truncate a table even if a foreign key constraint exists. – max Sep 06 '16 at 14:17
  • I included 'Resetable' in the controller and put the function in the 'helper', I have this error: ` undefined method `truncate!' for #` and the variable model is Student, the first model that I passed – Patrick Barattin Sep 06 '16 at 14:19
  • Modules and helpers are not the same thing. The above is a module that is mixed into the model class to extend it. A helper is mixed into the controller which is not what you want. – max Sep 06 '16 at 14:51
  • You should be including Resetable in the Student class. Follow the example in the answer instead. – max Sep 06 '16 at 14:52
0

I pluck some code from following SO answers

You can add something like this in controller

def reset_db
  conn = ActiveRecord::Base.connection
  tables = ActiveRecord::Base.connection.tables
  tables.each { |t| conn.execute("TRUNCATE #{t}") }

  Rails.application.load_seed
end
Community
  • 1
  • 1
Deepak Mahakale
  • 22,834
  • 10
  • 68
  • 88
  • Thanks this is a good idea, but I have a problem, because I'm using Postgresql and id not always starts at 1, otherwise the relationship in the seed does not work ... How can I set the first id 1? I think this is function called 'sequence' – Patrick Barattin Sep 06 '16 at 13:57
  • I tried this feature but it gives me this error: `PG::UndefinedObject: ERROR: unrecognized configuration parameter "tables" : show tables` – Patrick Barattin Sep 06 '16 at 14:04
  • In postgres its `SELECT tablename FROM pg_tables` but you might as well use the higher level `ActiveRecord::Base.connection.tables` which is provided by the adapter. – max Sep 06 '16 at 14:12
  • @Deepak is conn correct? Because I get this error `undefined local variable or method `conn' for #<#:0x00559613c67c40>` – Patrick Barattin Sep 06 '16 at 14:28
  • Edited, you need the connection – Deepak Mahakale Sep 06 '16 at 14:44
  • ok, but now I get this error `undefined method `to_model' for true:TrueClass` – Patrick Barattin Sep 06 '16 at 15:08
  • @Deepak now it work but there is an error that i get: Migrations are pending... maybe i don't have to delete something? – Patrick Barattin Sep 11 '16 at 19:15