如何在执行 rake db:setup 之前检查数据库是不是存在于 Rails 中

Posted

技术标签:

【中文标题】如何在执行 rake db:setup 之前检查数据库是不是存在于 Rails 中【英文标题】:How to check if the database exists or not in rails before doing a rake db:setup如何在执行 rake db:setup 之前检查数据库是否存在于 Rails 中 【发布时间】:2013-06-13 13:22:14 【问题描述】:

在执行 rake db:setup 之前如何检查数据库是否存在于 Rails 中?

我想在 db:create 完成之前检查数据库是否已经存在。到目前为止,我还没有在 Rails 中看到具体的方法,但我知道这可以使用 mysql 脚本来完成

【问题讨论】:

为什么要这样做?即使数据库已经存在,rake db:create 也不会失败。它打印一条消息说该消息已经存在 我正在运行一个厨师食谱,它会这样做......所以食谱在该消息之后停止。如果数据库存在,我希望它跳过 rake db:create 并继续 是否引发异常?如果是这样,您可以将其放在开始救援块中并继续此错误 【参考方案1】:

这是一个检查数据库是否已经存在的方法:

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

参考文献

ActiveRecord::Base.connection ActiveRecord::NoDatabaseError

【讨论】:

我已经将Dwayne Crook's solution above 变成了宝石:activerecord-db_exists。希望能帮助到你。 :)【参考方案2】:

我做了一个 rake 任务,扩展了之前的一些答案。我在 Vagrant+Docker 设置中经常使用它,因此我可以非常轻松地发出单个命令,然后创建新数据库或发出迁移到当前数据库。我使用branched database 范式进行开发。我经常需要播种一个新数据库或更新我现有的数据库。

在 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

所以现在我可以运行一个简单的 bash 命令:

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

然后我将其进一步自动化为 Makefile(为简洁起见):

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

翻译成:

make database

满足我所有的本地数据库需求。

【讨论】:

可以用Rake::Task['environment'].invoke代替task :exists => :environment吗? 不,因为我不希望先决条件任务的执行在我有机会捕获错误并静默返回之前失败。此任务的目的是查看它是否有效,然后静默返回 0/1 状态,并且您必须将对环境任务的调用包装在 begin/rescue 块中以检查通过/失败状态而不是 get一个充满回溯的巨大屏幕。 这里请注意。最好挽救一个特定的错误,而不是挽救 StandardError(这是没有参数的挽救方法的默认值)。请参阅***.com/questions/10048173/… 了解更多信息。 也许您希望环境任务失败,只是为了确保您在执行此任务时正确设置了环境。我会写task exists: :environment do 来避免调用。【参考方案3】:

如果数据库尚不存在,您还可以指望rake db:migrate 返回错误。

我在我的脚本中使用了类似的东西:

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

(灵感来自 [penguincoder]

请注意,这仅在表达式的退出代码很重要(考虑任何类型的管道)之类的原始问题问题(请参阅问题本身下方作者的其他 cmets)之类的情况下有用:在大多数情况下@ 987654323@ 的作用与rake db:migrate 2>/dev/null || rake db:setup 完全相同,但退出代码除外。

【讨论】:

我强烈建议不要这样做。如果您的 db:migrate 命令因任何原因失败,则运行 setup 命令。 db:setup 将截断任何现有错误,因此如果您的迁移因任何原因失败,您将丢失所有数据, 如果数据库已经存在,@JamesRocker rake db:setup 不会弄乱您的数据,但这也意味着rake db:migrate 2>/dev/null || 是无用的,除非您想做(rake db:migrate 2>/dev/null || rake db:setup) && <something that depends on the final existence of the database>。我会相应地编辑答案。 @jamesrocker 上面的注释应该是:rake db:setup 不会在数据库已经存在的情况下混淆您的数据,无论迁移的结果如何。【参考方案4】:

以下是我为此目的制作的一些 bash 脚本:

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

这些检查是否存在schema_migrations 表以确定rake db:setup 之前是否已运行。

【讨论】:

【参考方案5】:

如果数据库不存在或连接不活跃(至少在 Rails 4+ 中),这将返回 false。

::ActiveRecord::Base.connection_pool.with_connection(&:active?) rescue false

【讨论】:

【参考方案6】:

Rails 6 现在有一个rails db:prepare 任务。

db:prepare 将运行 db:migrate。如果db:migrate 失败,则运行db:createdb:seed,然后运行db:migrate

使用rails --tasks查看所有rails任务

...
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)
...

注意: db:setup 将删除数据库中当前的所有数据。 见Joshua Pinters'scomment。

【讨论】:

注意,rails db:setup 将删除数据库中的所有数据,如果它已经存在的话。我没有发现超级直观,特别是考虑到行尾的注释:“(使用 db:reset 也先删除数据库)”。【参考方案7】:

试试这个

 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

【讨论】:

【参考方案8】:

这是我用来检查数据库状态的:

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

【讨论】:

以上是关于如何在执行 rake db:setup 之前检查数据库是不是存在于 Rails 中的主要内容,如果未能解决你的问题,请参考以下文章

如何从 rake 任务中提前返回?

强制 Rake 任务在特定的 Rails 环境中运行

如何在 ruby​​ on rails 的亚马逊 aws 服务器中使用 gem 执行 rake 任务?

自动执行 rake 任务以在 heroku 上启动时运行?

如何在'rake test'中关闭警告'ruby -w'?

在“rake test”之后执行 rake 任务