如何将多个模式加载到 Rails 引擎或应用程序中?

Posted

技术标签:

【中文标题】如何将多个模式加载到 Rails 引擎或应用程序中?【英文标题】:How to load multiple schemas into a Rails engine or app? 【发布时间】:2016-03-28 06:10:17 【问题描述】:

寻求将我所有的共享模型移动到一个引擎,该引擎可以包含在我的每个微应用中。

这个引擎应该为我们所有的遗留数据提供一个模型层,包括:

模型文件 架构文件 迁移(我们关注 Pivotal Labs' pattern,这不是问题)

模型文件正在自动修补,这很好。

正在使用 Nikolay Strum's db.rake 对架构文件进行猴子修补:

namespace :db do
  namespace :schema do
    # desc 'Dump additional database schema'
    task :dump => [:environment, :load_config] do
      filename = "#Rails.root/db/foo_schema.rb"
      File.open(filename, 'w:utf-8') do |file|
        ActiveRecord::Base.establish_connection("foo_#Rails.env")
        ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
      end
    end
  end

  namespace :test do
    # desc 'Purge and load foo_test schema'
    task :load_schema do
      # like db:test:purge
      abcs = ActiveRecord::Base.configurations
      ActiveRecord::Base.connection.recreate_database(abcs['foo_test']['database'], mysql_creation_options(abcs['foo_test']))
      # like db:test:load_schema
      ActiveRecord::Base.establish_connection('foo_test')
      ActiveRecord::Schema.verbose = false
      load("#Rails.root/db/foo_schema.rb")
    end
  end
end

我们需要rake db:createrake db:schema:load 才能工作,

db.rake 补丁只影响db:schema:dumpdb:test:load_schema(我假设是tests_prepare 的一部分)。我尝试使用以下方法将它们修补到db:schema:load

namespace :db do

  # Helpers
  def mysql_creation_options(config)
    @charset   = ENV['CHARSET']   || 'utf8'
    @collation = ENV['COLLATION'] || 'utf8_unicode_ci'
    :charset => (config['charset'] || @charset), :collation => (config['collation'] || @collation)
  end

  def load_schema(schema_name)
    abcs = ActiveRecord::Base.configurations
    ActiveRecord::Base.connection.recreate_database(abcs[schema_name+'_test']['database'], mysql_creation_options(abcs[schema_name+'_test']))
    # like db:test:load_schema
    ActiveRecord::Base.establish_connection(schema_name+'_test')
    ActiveRecord::Schema.verbose = false
    load("#Rails.root/db/#schema_name_schema.rb")
  end

  namespace :schema do
    # desc 'Dump additional database schema'
    task :dump => [:environment, :load_config] do
      dump_schema = -> (schema_name) 
        filename = "#Rails.root/db/#schema_name_schema.rb"
        File.open(filename, 'w:utf-8') do |file|
          ActiveRecord::Base.establish_connection("#schema_name_#Rails.env")
          ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
        end
      

      dump_schema.call('kiddom')
      dump_schema.call('kiddom_warehouse')
    end

    # When loading from schema, load these files, too
    task :load => [:environment, :load_config] do
      load_schema('kiddom')
      load_schema('kiddom_warehouse')
    end
  end

  namespace :test do
    # desc 'Purge and load foo_test schema'
    task :load_schema do
      load_schema('kiddom')
      load_schema('kiddom_warehouse')
    end
  end
end

但这给了我错误NoMethodError: undefined method 'recreate_database' for #<ActiveRecord::ConnectionAdapters::SQLite3Adapter:0x007feb6bb43558>。显然,这只适用于 Oracle 类型的数据库?

我试图影响额外的schema.rb 的底层DROPCREATE DATABASE sql 的Rails 命令是什么?

【问题讨论】:

我曾经使用过一个包含模型的引擎。我们只共享模型和迁移,并且效果很好。我们为每个应用单独保存的schema.rb;引擎没有提供。恕我直言,这是有道理的,因为数据库属于应用程序,而不是引擎。 HTH 谢谢拉斐尔!在大多数情况下,您是完全正确的:引擎添加新模型代码或扩展现有模型,让 schema.rb 存在于应用程序中是有意义的。然而,在我们的例子中,引擎表示存在于完全不同数据库中的模型 - 所以我们需要为这些模型提供不同的模式文件(对吗?) 我明白了。我从来没有使用过多个数据库,尽管我一直很好奇如何做到这一点。显然,您可以在每个模型类的基础上使用不同的数据库。如果您还需要在其他数据库上运行迁移,它会变得有点棘手;见excid3.com/blog/… 您是否尝试过在ActiveRecord::Tasks 中使用dropcreate 方法? :api.rubyonrails.org/classes/ActiveRecord/Tasks/… 【参考方案1】:

您正在使用 SQLite 作为数据库引擎。希望这是你想做的。

由于您正在创建 SQLite 数据库,因此与其他数据库适配器(如 MySQLAdpter 或 Postgress)有些不同。

在 MySQL 的情况下,必须在使用“CREATE DATABASE ...” SQL 命令建立连接之前创建数据库。所以你必须在建立连接之前创建数据库。

但在 SQLite 的情况下,由于数据库驻留在一个文件中,一个文件只能包含一个数据库,因此没有单独的步骤来创建数据库。尝试建立与数据库本身的连接将导致创建数据库文件。

因此 create_database 方法在使用 SQLiteAdapter 时将不起作用。您可以简单地从代码中删除该行。

您可以查看 Rake 任务 db:create 的源代码

https://github.com/rails/rails/blob/f47b4236e089b07cb683ee9b7ff8b06111a0ec10/activerecord/lib/active_record/railties/databases.rake

另外,SQLiteDatabaseTasks 中“create”方法的源代码。可以看到,它只是调用了建立连接方法

https://github.com/rails/rails/blob/f47b4236e089b07cb683ee9b7ff8b06111a0ec10/activerecord/lib/active_record/railties/databases.rake

【讨论】:

以上是关于如何将多个模式加载到 Rails 引擎或应用程序中?的主要内容,如果未能解决你的问题,请参考以下文章

如何清理或销毁 QJSEngine?

Ruby on Rails 3 - 为每个请求重新加载 lib 目录

如何将远程(用户)IP 从 nginx 传递到托管在 google 容器引擎上的 Rails?

如何将多个文件模式加载到数据库中?

谷歌应用引擎:隐藏 Rails 密钥的最佳实践?

在 Rails 引擎中加载多个配置文件