如何将多个模式加载到 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:create
和rake db:schema:load
才能工作,
db.rake
补丁只影响db:schema:dump
和db: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
的底层DROP
和CREATE DATABASE
sql 的Rails 命令是什么?
【问题讨论】:
我曾经使用过一个包含模型的引擎。我们只共享模型和迁移,并且效果很好。我们为每个应用单独保存的schema.rb
;引擎没有提供。恕我直言,这是有道理的,因为数据库属于应用程序,而不是引擎。 HTH
谢谢拉斐尔!在大多数情况下,您是完全正确的:引擎添加新模型代码或扩展现有模型,让 schema.rb 存在于应用程序中是有意义的。然而,在我们的例子中,引擎表示存在于完全不同数据库中的模型 - 所以我们需要为这些模型提供不同的模式文件(对吗?)
我明白了。我从来没有使用过多个数据库,尽管我一直很好奇如何做到这一点。显然,您可以在每个模型类的基础上使用不同的数据库。如果您还需要在其他数据库上运行迁移,它会变得有点棘手;见excid3.com/blog/…
您是否尝试过在ActiveRecord::Tasks
中使用drop
和create
方法? :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 引擎或应用程序中?的主要内容,如果未能解决你的问题,请参考以下文章
Ruby on Rails 3 - 为每个请求重新加载 lib 目录