Rails:如何在Rails中创建子目录中的迁移?

6

我正在编写一款SaaS模式的应用程序。 我的应用程序数据库由两个逻辑部分组成:

  • 应用程序表格 - 比如用户,角色...
  • 用户定义的表格(他可以从UI级别生成它们),对于每个应用程序实例都可能不同

所有的表格都是通过rails迁移机制创建的。

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

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

这样我就可以在db/migrations/custom上做svn:ignore,当我在客户服务器上更新我的应用程序时,它只会更新应用程序表格迁移。

在Rails中有没有实现这种方法的方式?


我正在使用 https://github.com/thuss/standalone-migrations 来解决这个问题。 - eebbesen
5个回答

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

现在你可以运行rake db:custom_migrate来运行位于db/migrate/custom的迁移。但它不会使用默认路径下的迁移。
你可能想要阅读ActiveRecord迁移的源代码。 点击这里

4

如果你正在使用Sinatra并且构建自己的rake任务,可以按照以下步骤操作:

require './app'
require 'sinatra/activerecord/rake'

ActiveRecord::Migrator.migrations_paths = 'your/path/goes/here'

当你运行rake -T命令时,会得到db命名空间:
rake db:create_migration  # create an ActiveRecord migration
rake db:migrate           # migrate the database (use version with VERSION=n)
rake db:rollback          # roll back the migration (use steps with STEP=n)

3

更新Rails 5/6版本;

Rails 5建议在config/database.yml文件中设置额外的迁移路径。非常简单,参见以下示例;

development:
  migrations_paths:
  - db/migrations
  - db/migrations/custom

ActiveRecord::Migrator.migrations_path=将在Rails 6中废弃。


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

现在,由用户生成的所有迁移都创建在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

用户创建自定义表后,我使用以下代码调用此迁移:
Rake::Task["db:migrate:redo"].execute("VERSION=20110108213453")

0

使用 Rails 4,我们可以看到迁移目录存储在一个由"db/migrate"访问的数组中

来自 activerecord/lib/active_record/migration.rb 的代码片段

def migrations_paths
    @migrations_paths ||= ["db/migrate"]
    # just to not break things if someone uses: migrations_path = some_string
    Array(@migrations_paths) # Data stored in an array
end

所以我们可以在 environment.rb 中使用 config 来向这个数组添加内容,作为一个例子

Rails.application.configure do
    config.paths["db/migrate"] << %Q{db/migrations}
    config.paths["db/migrate"] << %Q{db/migrations.custom}
end

还有,我找不到文档,但是db/migrate下的其他目录也会被搜索和执行。

例如,我将迁移分组放入发布目录中。

-db/migrate
    -3.0.0
       XXXXXcreate_user.rb
    -3.0.1
       XXXXXcreate_task.rb

这个机制也用于添加引擎迁移目录在这里讨论


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接