From 9d65a4e29dc168be15f0c4a40bf7e7cbe7221319 Mon Sep 17 00:00:00 2001 From: Niki Date: Wed, 11 Jun 2025 18:24:07 +0200 Subject: [PATCH] add rails tenant:migrate task --- lib/tasks/tenant.rake | 90 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 lib/tasks/tenant.rake diff --git a/lib/tasks/tenant.rake b/lib/tasks/tenant.rake new file mode 100644 index 0000000..b545b92 --- /dev/null +++ b/lib/tasks/tenant.rake @@ -0,0 +1,90 @@ +namespace :tenant do + desc "Migrate all tenant schemas" + task migrate: :environment do + # First migrate the public schema (organizations table, etc.) + puts "Migrating public schema..." + ActiveRecord::MigrationContext.new(Rails.application.paths["db/migrate"].first).migrate + + # Then migrate all tenant schemas + puts "Migrating all tenant schemas..." + SchemaManager.migrate_all_schemas + + puts "All schemas migrated successfully!" + end + + desc "Migrate specific tenant schema" + task :migrate_one, [:subdomain] => :environment do |task, args| + subdomain = args[:subdomain] + organization = Organization.find_by!(subdomain: subdomain) + + puts "Migrating schema for #{organization.name}..." + organization.with_schema do + ActiveRecord::MigrationContext.new(Rails.application.paths["db/migrate"].first).migrate + end + puts "Migration complete!" + end + + desc "Rollback all tenant schemas" + task :rollback, [:step] => :environment do |task, args| + step = (args[:step] || 1).to_i + + Organization.find_each do |org| + puts "Rolling back #{step} step(s) for #{org.name}..." + org.with_schema do + ActiveRecord::MigrationContext.new(Rails.application.paths["db/migrate"].first).rollback(step) + end + end + end + + desc "Show migration status for all tenants" + task status: :environment do + Organization.find_each do |org| + puts "\n#{org.name} (#{org.subdomain}):" + org.with_schema do + migration_context = ActiveRecord::MigrationContext.new(Rails.application.paths["db/migrate"].first) + migration_context.migrations_status.each do |status, version, name| + puts " #{status.center(8)} #{version} #{name}" + end + end + end + end + + desc "Create a new tenant" + task :create, [:name, :subdomain] => :environment do |task, args| + name = args[:name] + subdomain = args[:subdomain] + + if name.blank? || subdomain.blank? + puts "Usage: rails tenant:create[name,subdomain]" + puts "Example: rails tenant:create['Acme Corp','acme']" + exit 1 + end + + organization = Organization.create!(name: name, subdomain: subdomain) + puts "Created organization: #{organization.name}" + puts "Schema: #{organization.schema_name}" + puts "Access at: http://#{subdomain}.localhost:3000" + end + + desc "Drop a tenant schema" + task :drop, [:subdomain] => :environment do |task, args| + subdomain = args[:subdomain] + + if subdomain.blank? + puts "Usage: rails tenant:drop[subdomain]" + exit 1 + end + + organization = Organization.find_by!(subdomain: subdomain) + + print "Are you sure you want to drop #{organization.name}? (y/N): " + response = STDIN.gets.chomp.downcase + + if response == 'y' || response == 'yes' + organization.destroy + puts "Dropped organization: #{organization.name}" + else + puts "Cancelled" + end + end +end