32

How to check if the database exists or not in rails before doing a rake db:setup?

I would like to check if a database already exists before a db:create is being done . I have not seen a specific way in rails so far but i know this can be done using mysql scripts

Bearish_Boring_dude
  • 547
  • 1
  • 6
  • 17
  • 3
    Why do you want to? `rake db:create` will not fail even if the database already exists. It prints a message saying that the message already exists – usha Jun 17 '13 at 14:46
  • i am running a chef cookbook that does that ...so the cookbook stops after that message. I want it to skip the rake db:create and continue if the database exists – Bearish_Boring_dude Jun 17 '13 at 14:48
  • Is it raising an exception? If so you can put it in a begin rescue block and continue on this error – usha Jun 17 '13 at 15:03

8 Answers8

30

Here is a method that checks if the database already exists:

def database_exists?
  ActiveRecord::Base.connection
rescue ActiveRecord::NoDatabaseError
  false
else
  true
end

References

Dwayne Crooks
  • 2,558
  • 21
  • 26
  • 1
    I've turned the [Dwayne Crook's](http://stackoverflow.com/users/391924/dwayne-crooks) [solution above](http://stackoverflow.com/a/25592558/1300227) into a gem: [activerecord-db_exists](https://rubygems.org/gems/activerecord-db_exists). Hope it helps. :) – SimonHildebrandt Aug 09 '16 at 05:23
  • This is the best solution because it specifically rescues the error in question `ActiveRecord::NoDatabaseError`. Other errors may reflect a bad connection, wrong port, wrong host, wrong password, etc - in which case we don't want to continue running db commands. – Mario Saraiva Mar 18 '22 at 16:25
28

I made a rake task that expands on some of the previous answers. I use this a lot in a Vagrant+Docker setup, so I can very easily issue a single command and either create a new database or issue a migrate to the current database. I use a branched database paradigm for development. I constantly need to seed a new database or update my existing one.

In lib/tasks/db_exists.rake:

namespace :db do
  desc "Checks to see if the database exists"
  task :exists do
    begin
      Rake::Task['environment'].invoke
      ActiveRecord::Base.connection
    rescue
      exit 1
    else
      exit 0
    end
  end
end

So now I can run a simple bash command:

rake db:exists && rake db:migrate || rake db:setup

Which I have then further automated into a Makefile (trimmed for brevity):

.PHONY database
database:
        rake db:exists && rake db:migrate || rake db:setup

Translates into:

make database

For all of my local database needs.

penguincoder
  • 497
  • 7
  • 8
  • 3
    Instead of `Rake::Task['environment'].invoke`, can you do `task :exists => :environment`? – nicholaides Mar 05 '16 at 02:32
  • 1
    No, because I don't want the execution of a prerequisite task to fail before I have a chance to trap the error and return silently. The intention of this task is to see if it works and then silently return a 0/1 status, and you have to wrap the call to the environment task in the begin/rescue block in order to check for pass/fail status and not get a giant screen full of backtrace. – penguincoder Jul 22 '16 at 11:48
  • 1
    Just a word of caution here. It's better to rescue a specific error as opposed to rescuing StandardError (which is the default for rescue method without arguments). See https://stackoverflow.com/questions/10048173/why-is-it-bad-style-to-rescue-exception-e-in-ruby for more. – wondersz1 May 12 '18 at 10:02
  • 1
    Maybe you want the environment task to fail, just to be sure you have your environment properly setup when executing this task. I would have written `task exists: :environment do` to avoid the invoke. – Capripot Nov 26 '19 at 20:05
17

You can also count on the fact that rake db:migrate returns an error if the database does not yet exist.

I used something like this in my scripts:

rake db:migrate 2>/dev/null || rake db:setup

(Inspired by [penguincoder]

Remark that this is only useful in cases like the original question's issue (see the additional comments of the author below the question itself) where the exit code of the expression matters (think of any sort of pipeline): in most cases rake db:setup will do exactly the same as rake db:migrate 2>/dev/null || rake db:setup, except for the exit code.

bert bruynooghe
  • 2,819
  • 1
  • 19
  • 18
  • 1
    I would strongly recommend against doing this. If your db:migrate command fails for any reason then the setup command is run. db:setup will truncate any existing error so if your migration fails for any reason, you lose all your data, – James Rocker Nov 08 '21 at 10:49
  • @JamesRocker `rake db:setup` does not mess with your data if the database already exists, but that also means that `rake db:migrate 2>/dev/null ||` is useless unless you want to do `(rake db:migrate 2>/dev/null || rake db:setup) && `. I'll edit the answer accordingly. – bert bruynooghe Nov 17 '21 at 10:22
  • @jamesrocker Above comment should read: `rake db:setup` does never mess with your data if the database already exists, no matter the result of the migration. – bert bruynooghe Nov 17 '21 at 10:41
8

Here are some bash scripts I made for this purpose:

Postgres

if echo "\c $PGDATABASE; \dt" | psql | grep schema_migrations 2>&1 >/dev/null
then
   bundle exec rake db:migrate
else
   bundle exec rake db:setup
fi

Mysql

 if echo "use $MYSQLDATABASE; show tables" | mysql | grep schema_migrations 2>&1 > /dev/null
 then
     bundle exec rake db:migrate
 else
     bundle exec rake db:setup
 fi

These check for the presence of the schema_migrations table to determine whether rake db:setup has been run previously.

Cameron Martin
  • 5,902
  • 2
  • 37
  • 52
6

This will return false if the DB doesn't exist or if the connection is not active (at least in Rails 4+).

::ActiveRecord::Base.connection_pool.with_connection(&:active?) rescue false
aruanoc
  • 817
  • 1
  • 7
  • 9
5

Rails 6 now has a rails db:prepare task.

db:prepare will run db:migrate. If db:migrate fails, then db:create, db:seed, followed by db:migrate are run.

See all rails tasks with rails --tasks

...
rails db:exists                             # Checks to see if the database exists
...
rails db:prepare                            # Runs setup if database does not exist, or runs migrations if it does
...
rails db:setup                              # Creates the database, loads the schema, and initializes with the seed data (use db:reset to also drop the database first)
...

NOTE: db:setup will remove any data currently in the database. See Joshua Pinters's comment.

natemacinnes
  • 154
  • 3
  • 8
  • 1
    Note, `rails db:setup` will remove all the data in the database, if it exists already. I didn't find that super intuitive, especially considering the comment at the end of the line: "(use db:reset to also drop the database first)". – Joshua Pinter Jan 16 '22 at 02:21
0

TRY THIS

 IF EXISTS 
       (
         SELECT name FROM master.dbo.sysdatabases 
        WHERE name = N'New_Database'
        )
    BEGIN
        SELECT 'Database Name already Exist' AS Message
    END
    ELSE
    BEGIN
        CREATE DATABASE [New_Database]
        SELECT 'New Database is Created'
    END
Kovid Purohit
  • 237
  • 1
  • 4
  • 14
0

Here is what I use to check the state of the DB:

if db_version=$(bundle exec rake db:version 2>/dev/null)
then
    if [ "$db_version" = "Current version: 0" ]; then
        echo "DB is empty"
    else
        echo "DB exists"
    fi
else
    echo "DB does not exist"
fi
Thomas
  • 9,928
  • 4
  • 26
  • 35