在标准“生产”或“开发”之外的不同数据库上使用Rails迁移

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在标准“生产”或“开发”之外的不同数据库上使用Rails迁移相关的知识,希望对你有一定的参考价值。

我有一个运行的rails项目,它定义了标准生产:,:开发和:在config / database.yml中测试数据库连接

另外我有一个quiz_development:和quiz_production:定义指向不同的主机/ db / user / password

我现在的目标是定义一个使用“quiz_#{RAILS_ENV}”作为其数据库配置的迁移。

我尝试过(并且失败了):

  • 在迁移文件中设置ActiveRecord :: Base.connection
  • 在rails中更改db:migrate任务以在那里设置ActiveRecord :: Base.connection

题:

如何使rake db:migrate使用其他数据库定义?

谢谢,弗兰克

答案

有点晚了,但我今天正在处理这个问题,我想出了这个自定义rake任务:

namespace :db do
  desc "Apply db tasks in custom databases, for example  rake db:alter[db:migrate,test-es] applies db:migrate on the database defined as test-es in databases.yml"
  task :alter, [:task,:database] => [:environment] do |t, args|
    require 'activerecord'
    puts "Applying #{args.task} on #{args.database}"
    ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations[args.database])
    Rake::Task[args.task].invoke
  end
end
另一答案

在rails 3.2中,为迁移添加连接方法不起作用。所以所有答案都是如此

def connection
 @connection ||= ActiveRecord::Base.establish_connection
end

根本不起作用(不能down,不能与change,连接丢失等)。原因是ActiveRecord :: Migration和Migrator类的连接硬编码为ActiveRecord :: Base all over the place

幸运的是,this post向我指出this ticket有一个很好的解决方案,即压倒实际的rake task

我最终使用了一个略有不同的rake任务,因此我可以具体说明我在不同数据库上运行的迁移(我们试图支持多个db版本):

这是我的lib / task / database.rake

# Augment the main migration to migrate your engine, too.
task 'db:migrate', 'nine_four:db:migrate'

namespace :nine_four do
    namespace :db do
        desc 'Migrates the 9.4 database'
        task :migrate => :environment do
            with_engine_connection do
                ActiveRecord::Migrator.migrate("#{File.dirname(__FILE__)}/../../nine_four/migrate", ENV['VERSION'].try(:to_i))
            end
        end
    end
end

# Hack to temporarily connect AR::Base to your engine.
def with_engine_connection
    original = ActiveRecord::Base.remove_connection
    ActiveRecord::Base.establish_connection("#{ Rails.env }_nine_four")
    yield
ensure
    ActiveRecord::Base.establish_connection(original)
end

这允许我们将特定于一个数据库的迁移放在它们自己的子目录中(nine_four / migrations而不是db / migrations)。它还为每个数据库提供了模式和迁移版本的完全隔离。唯一的缺点是要运行两个rake任务(db:migrate和nine_four:db:migrate)。

另一答案

除了在不同的环境中运行迁移之外,我还希望将模式放在单独的文件中。您可以从命令行执行此操作:

RAILS_ENV=quiz_development SCHEMA=db/schema_quiz_development.rb rake db:migrate

但我喜欢自定义rake任务方法,所以我可以输入:

rake db:with[quiz_development, db:migrate]

这是rake任务:

namespace :db do
  desc "Run :task against :database"
  task :with, [:database,:task] => [:environment] do |t, args|
    puts "Applying #{args.task} to #{args.database}"
    ENV['SCHEMA'] ||= "#{Rails.root}/db/schema_#{args.database}.rb"
    begin
      oldRailsEnv = Rails.env
      Rails.env = args.database
      ActiveRecord::Base.establish_connection(args.database)
      Rake::Task[args.task].invoke
    ensure
      Rails.env = oldRailsEnv
    end
  end
end
另一答案

我发现了一个非常干净的方法:

class CreateScores < ActiveRecord::Migration

  class ScoresDB < ActiveRecord::Base
    establish_connection("scores_#{Rails.env}")
  end

  def connection
    ScoresDB.connection
  end

  def up
    create_table :scores do |t|
      t.text :account_id
      t.text :offer
    end
  end

  def down
    drop_table :scores
  end
end
另一答案
class Article < ActiveRecord::Base

    ActiveRecord::Base.establish_connection(
      :adapter  => "mysql2",
      :host     => "localhost",
      :username => "root",
      :database => "test"
    )
end

和:

class Artic < Aritcle
    self.table_name = 'test'

    def self.get_test_name()
        query = "select name from testing"
        tst = connection.select_all(query) #select_all is important!
        tst[0].fetch('name')
    end
end

您可以调用Artic.get_test_name来执行。

另一答案

你可以使用这个版本,它也支持rake db:rollback

class ChangeQuiz < ActiveRecord::Migration
  def connection
    ActiveRecord::Base.establish_connection("quiz_#{Rails.env}").connection
  end

  def reset_connection
    ActiveRecord::Base.establish_connection(Rails.env)
  end

  def up
    # make changes

    reset_connection
  end

  def self.down
    # reverse changes

    reset_connection
  end
end
另一答案

您是否尝试过将quiz_development用作RAILS_ENV(而不是试图让它使用"quiz_#{RAILS_ENV}")?

RAILS_ENV=quiz_development rake db:migrate
另一答案

您还可以将所有与quiz_相关的迁移移动到db /目录中的单独子文件夹中,然后添加镜像常规迁移功能但在该子目录中查找迁移的rake任务。可能不是超级优雅但它有效。您可以复制并粘贴已经在rails中的rake任务,只需稍微修改它们即可。

另一答案

基于@TheDeadSerious的回答:

module ActiveRecord::ConnectionSwitch  
  def on_connection(connection_spec_name)
    raise ArgumentError, "No connection specification name specified. It should be a valid spec from database.yml" unless connection_spec_name
    ActiveRecord::Base.establish_connection(connection_spec_name)
    yield
  ensure
    ActiveRecord::Base.establish_connection(Rails.env)
  end
end

ActiveRecord.send :extend, ActiveRecord::ConnectionSwitch

用法:

ActiveRecord.on_connection "sdmstore_#{Rails.env}" do
  Widget.delete_all
end
另一答案

如果你想在你的rails网站上显示wordpress帖子,你不想使用多魔法连接gem。您可以使用以下代码从wordpress博客获取数据。

 class Article < ActiveRecord::Base

    ActiveRecord::Base.establish_connection(
     :adapter  => "mysql2",
     :host     => "localhost",
     :username => "root",
     :database => "blog"
    )

    self.table_name = 'wp_posts'

    def self.get_post_data()
        query = "select name from testing"
        tst = connection.select_all(query)
        tst[0].fetch('name')
    end
end
另一答案

我通过为不同的数据库创建单独的连接器类并在迁移中使用它来实现此目的。

class AddExampleToTest < ActiveRecord::Migration
  def connection
    @connection = OtherDatabaseConnector.establish_connection("sdmstore_#{Rails.env}").connection
  end
  def up
    add_column :test, :example, :boolean, :default => true

    @connection = MainDatabaseConnector.establish_connection("#{Rails.env}").connection
  end
  def down
    remove_column :test, :example

    @connection = MainDatabaseConnector.establish_connection("#{Rails.env}").connection
  end
end

我们可以在初始化器中定义这些连接器类。

class MainDatabaseConnector < ActiveRecord::Base
end
class OtherDatabaseConnector < ActiveRecord::Base
end

ActiveRecord :: Base保留一个连接池,该连接池是由类索引的哈希。 Read more here。因此,使用单独的类进行单独的连接可以保护我们免受关闭的连接错

此外,使用updown而不是change允许我们回滚迁移没有任何问题。仍然没有想出这个的原因。

另一答案

有一个更简单的答案。将此添加到您的迁移中:

def connection
  ActiveRecord

以上是关于在标准“生产”或“开发”之外的不同数据库上使用Rails迁移的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 系列 生产标准线上环境安装配置案例及棘手问题解决

Go RabbitMQ

怎么搭建的java开发,测试,生产环境的

在开发和生产环境中使用不同的 Web.config

用于测试和开发配置文件的不同数据库

如何根据生产或开发模式读取不同的 .env 文件?