【问题标题】:Rails: How to create migration in subdirectory with Rails?Rails:如何使用 Rails 在子目录中创建迁移?
【发布时间】:2011-01-08 19:42:37
【问题描述】:

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

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

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

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

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

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

有没有办法在 Rails 中实现这一点?

【问题讨论】:

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


【解决方案1】:

任务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 迁移。

【讨论】:

    【解决方案2】:

    如果您正在使用 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 中被弃用。

      【讨论】:

        【解决方案4】:

        @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 目录中创建。

        然后我编写了从 db/migrations/custom 目录执行所有迁移的普通 rails 迁移:

        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")
        

        【讨论】:

          【解决方案5】:

          使用 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
          

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-01-31
            • 1970-01-01
            • 2020-05-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多