Skip to content

Instantly share code, notes, and snippets.

@fernandoalmeida
Last active December 20, 2015 11:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save fernandoalmeida/6127626 to your computer and use it in GitHub Desktop.
Save fernandoalmeida/6127626 to your computer and use it in GitHub Desktop.
Rails multi-tenant / multi-database with subdomains using a control database
# config/application.rb
module MyApp
class Application < Rails::Application
def config.database_configuration
config = super
ActiveRecord::Base.establish_connection(config["control"])
Migration.all.each do |client|
config[client.subdomain] = config["control"].merge("database" => client.database, "host" => "...")
end
ActiveRecord::Base.establish_connection(config[Rails.env])
return config
end
end
end
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_filter :select_database
protected
def select_database
ActiveRecord::Base.establish_connection("control")
active_client = Client.active.where(:subdomain => subdomain).first
if !!active_client
begin
config = ActiveRecord::Base.connection_config.merge({
:database => active_client.database,
:host => "...",
:username => "...",
:password => "..."
})
rescue
ActiveRecord::Base.establish_connection("production")
# database connection error
# flash, log, redirect, etc
end
else
# inactive client or client not found
# flash, log, redirect, etc
end
end
def subdomain
!request.subdomain.empty? && request.host != "mydomain.com" ? request.subdomains.first : ""
end
end
# app/models/client.rb
class Client < ActiveRecord::Base
scope :active, where(:active => true)
attr_accessible :active, :subdomain, :database, :host, etc...
end
# lib/deploy/db.rb
namespace :deploy do
desc "Run migrate for all clients"
task :migrate_clients do
begin
run "cd #{current_path} && bundle exec rails runner -e production 'Migration.migrate'"
Capistrano::CLI.ui.say "\033[32m * success\033[0m"
rescue Exception => e
Capistrano::CLI.ui.say "\033[31m * error"
Capistrano::CLI.ui.say "*** [err] #{e.message}\033[0m"
end
end
end
# config/deploy.rb
after "deploy:migrate", "deploy:migrate_clients"
# app/models/migration.rb
class Migration < ActiveRecord::Base
self.table_name = "clients"
def self.migrate
default = ActiveRecord::Base.connection_config
ActiveRecord::Base.establish_connection("control")
Migration.all.each do |client|
ActiveRecord::Base.establish_connection(default.merge({
"database" => client.database,
"host" => "..."
}))
ActiveRecord::Migrator.migrate(ActiveRecord::Migrator.migrations_paths)
puts "\033[32m'#{client.name}' migrated successfully\033[0m"
end
ActiveRecord::Base.establish_connection(default)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment