Reputation: 7715
I'm writing a SaaS model application. My application database consist of two logic parts:
All tables are created by rails migrations mechanism.
I would like to put user-defined tables in another directory:
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?
Upvotes: 6
Views: 6314
Reputation: 71
Update for Rails 5/6;
Rails 5 recommends setting additional migration paths in your config/database.yml
file. It's very easy, see this example;
development:
migrations_paths:
- db/migrations
- db/migrations/custom
ActiveRecord::Migrator.migrations_path=
will be deprecated in Rails 6.
Upvotes: 4
Reputation: 56
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
Upvotes: 0
Reputation: 1086
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'
When you run 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)
Upvotes: 4
Reputation: 7715
@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")
Upvotes: 2
Reputation: 596
Task 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
with the following contents:
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
Now you can run rake db:custom_migrate
to run migrations which are located in db/migrate/custom
. But it will not use migrations from the default path.
You might want to read the source code for the ActiveRecord migrations.
Upvotes: 7