如何使用Rails在子目录中创建迁移?

Adr*_*fin 3 activerecord ruby-on-rails rails-migrations ruby-on-rails-3

我正在编写SaaS模型应用程序.我的应用程序数据库包含两个逻辑部分:

  • 应用程序表 - 例如用户,角色......
  • 用户定义的表(他可以从ui级别生成它们),每个应用程序实例可以有所不同

所有表都是由rails迁移机制创建的.

我想将用户定义的表放在另一个目录中:

  • db/migrations - 应用程序表
  • db/migrations/custom - 用户生成的表

所以我可以做svn:忽略db/migrations/custom,当我在客户端服务器上更新我的应用程序时,它只会更新应用程序表的迁移.

有没有办法在rails中实现这个目标?

小智 7

任务rake db:migrate具有迁移的硬编码路径.但是你可以创建自己的rake任务.例如,lib/tasks/custom_db_migrate.rake使用以下内容创建:

namespace :db do
  task :custom_migrate => :environment do
    ActiveRecord::Migration.verbose = ENV["VERBOSE"] ? ENV["VERBOSE"] == "true" : true
    ActiveRecord::Migrator.migrate("db/migrate/custom", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
    Rake::Task["db:schema:dump"].invoke if ActiveRecord::Base.schema_format == :ruby
  end
end
Run Code Online (Sandbox Code Playgroud)

现在,您可以运行rake db:custom_migrate以运行位于的迁移db/migrate/custom.但它不会使用默认路径中的迁移.

您可能希望阅读 ActiveRecord迁移的源代码.


Adr*_*fin 2

@Vasily 感谢您的回复。阅读完它并从 stackoverflow 中找到更多问题后,我想出了这个解决方案:

由于我编写自己的生成器来创建用户表,因此我在其中包含了 Rails::Generators::Migration ,这样我就可以重写 next_migration_number 方法,如下所示:

def self.next_migration_number(dirname)
 if ActiveRecord::Base.timestamped_migrations
   Time.now.utc.strftime("custom/%Y%m%d%H%M%S")
 else
   "custom/%.3d" % (current_migration_number(dirname) + 1)
 end
end
Run Code Online (Sandbox Code Playgroud)

现在用户生成的所有迁移都在 db/migrations/custom 目录中创建。

然后我编写了正常的 Rails 迁移,它执行 db/migrations/custom 目录中的所有迁移:

class ExecuteCustomMigrations < ActiveRecord::Migration
   MIGRATIONS_PATH='db/migrate/custom'
   def self.up
     Dir["#{MIGRATIONS_PATH}/[0-9]*_*.rb"].
     sort.map{|filename|require filename}.flatten.
     each{|class_name| const_get(class_name).up}
   end

   def self.down
     Dir["#{MIGRATIONS_PATH}/[0-9]*_*.rb"].sort.reverse.
     map{|filename|require filename}.flatten.
     each{|class_name| const_get(class_name).down}
   end
end
Run Code Online (Sandbox Code Playgroud)

用户创建自定义表后,我使用以下代码调用此迁移:

Rake::Task["db:migrate:redo"].execute("VERSION=20110108213453")
Run Code Online (Sandbox Code Playgroud)