34

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
  • 567
  • 1
  • 6
  • 18
  • 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

9 Answers9

36

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,737
  • 25
  • 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
31

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
  • 547
  • 7
  • 8
  • 3
    Instead of `Rake::Task['environment'].invoke`, can you do `task :exists => :environment`? – nicholaides Mar 05 '16 at 02:32
  • 3
    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
19

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

I'm using something like this in my scripts:

(rake db:migrate:status 2>/dev/null || rake db:setup) && rake db:migrate

(Inspired by [penguincoder]

bert bruynooghe
  • 2,985
  • 1
  • 20
  • 18
  • 2
    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
  • 1
    @JamesRocker I adapted the answer so it is using `db:migrate:status` instead. Although the `db:init` part of `db:setup` will not cause you to lose your data, the seeding and migration part of it might render errors, and hiding information using `rake db:migrate 2>/dev/null` can be a PITA. – bert bruynooghe Jul 18 '22 at 08:09
10

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
  • 304
  • 4
  • 10
  • 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
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,952
  • 2
  • 40
  • 53
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
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
  • 258
  • 1
  • 4
  • 15
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
  • 10,358
  • 4
  • 27
  • 35
0

My version in bash:

database_version() {
    local DB_VERSION=$(bundle exec rake db:version 2>/dev/null)

    if [[ "$DB_VERSION" =~ ^Current\ version\:\ ([[:digit:]]+)$ ]]; then
        if [[ "${BASH_REMATCH[1]}" != "" ]]; then
            echo $(("${BASH_REMATCH[1]}"))
        else
            echo -1
        fi
        return
    fi

    echo -1
}

if [[ $(($(database_version))) > 0 ]]; then
    echo "Database exists"
else
    echo "Database does not exist"
fi
Plivox
  • 21
  • 3