Rails: ¿Cómo crear una migración en un subdirectorio con Rails?

I'm writing a SaaS model application. My application database consist of two logic parts:

  • application tables - such as user, roles...
  • user-defined tables (he can generate them from UI level) that can be different for each application instance

All tables are created by rails migrations mechanism.

I would like to put user-defined tables in another directory:

  • db/migrations - application tables
  • db/migrations/custom - tables generated by user

so I can do svn:ignore on db/migrations/custom, and when I do updates of my app on clients servers it would only update application tables migrations.

Is there any way to achieve this in rails?

preguntado el 08 de enero de 11 a las 19:01

Estoy usando github.com/thuss/standalone-migrations to solve this challenge. -

5 Respuestas

Tarea rake db:migrate has a hard coded path to migrations. But you can create your own rake task. For example, create lib/tasks/custom_db_migrate.rake con los siguientes contenidos:

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

Ahora puedes correr rake db:custom_migrate to run migrations which are located in db/migrate/custom. But it will not use migrations from the default path.

Tu podrías querer read the source code for the ActiveRecord migrations.

Respondido el 09 de enero de 11 a las 00:01

If you're using Sinatra and building your own rake task, you can do the following:

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

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

Cuando corres rake -T, you'll get the db namespace:

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)

Respondido 05 Abr '13, 03:04

@Vasily thank's for your response. After reading it and couple more questions from stackoverflow I came up with this solution:

Since I write my own generator to create user tables I included Rails::Generators::Migration in it so I can override next_migration_number method like this:

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

Now all migrations generated by user are created in db/migrations/custom directory.

Then I wrote normal rails migration that executes all migrations from db/migrations/custom directory:

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

After user creates custom table i call this migration with this code:

Rake::Task["db:migrate:redo"].execute("VERSION=20110108213453")

Respondido el 09 de enero de 11 a las 13:01

Actualización para Rails 5/6;

Rails 5 recomienda establecer rutas de migración adicionales en su config/database.yml expediente. Es muy fácil, mira este ejemplo;

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

ActiveRecord::Migrator.migrations_path= quedará obsoleto en Rails 6.

Respondido 20 Feb 21, 23:02

With rails 4 we can see that migration directories are stored in an array accessed by "db/migrate"

Code snipit from 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

So we can add to this array with config in environment.rb, as an example

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

Also, I could not find this documented, but additional directories under db/migrate also get searched and executed.

e.g. I put groups of migrations into release directories

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

This mechanism is also used to add engine migration directories Discussed here

Respondido 06 Feb 18, 23:02

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.