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

时间:2011-01-08 19:42:38

标签: ruby-on-rails activerecord ruby-on-rails-3 rails-migrations

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

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

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

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

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

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

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

5 个答案:

答案 0 :(得分: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的迁移。但它不会使用默认路径中的迁移。

您可能希望read the source code进行ActiveRecord迁移。

答案 1 :(得分:3)

如果您正在使用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)

答案 2 :(得分: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")

答案 3 :(得分: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下的其他目录也会被搜索并执行。

e.g。我将迁移组放入发布目录

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

此机制还用于添加引擎迁移目录 Discussed here

答案 4 :(得分:0)

Rails 5/6更新;

Rails 5建议在config/database.yml文件中设置其他迁移路径。很简单,请参见此示例;

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

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