class Company < ActiveRecord::Base establish_connection "production" has_many :brands, dependent: :destroy validates :subdomain, :db_user, :db_host, :db_port, :name, presence: true end
class Brand < ActiveRecord::Base establish_connection "production" belongs_to :company validates :name, :db_name, presence: true end
MyApp::Application.routes.draw do scope ':brand' do resource :sessions, only: [:new, :create, :destroy] # .. match '/' => redirect("/%{brand}/orders"), as: 'brand_root' end root :to => "main#index" end
class ApplicationController < ActionController::Base protect_from_forgery before_filter :override_db before_filter :authenticate_user! def not_found raise ActionController::RoutingError.new('Not Found') end # scope, # , # # Ex: orders_path(brand: @current_brand.name) orders_path def url_options if @current_brand.present? { :brand => @current_brand.name }.merge(super) else super end end private # def override_db @current_company = Company.where("(subdomain = ? or alias = ?) AND active = ?", request.env['HTTP_HOST'][/^[\w\-]+/], request.env['HTTP_HOST'], true).first not_found unless @current_company.present? && @current_company.brands.present? if params[:brand].present? @current_brand = @current_company.brands.find_by_name params[:brand] if @current_brand.present? ActiveRecord::Base.clear_cache! ActiveRecord::Base.establish_connection( :adapter => "postgresql", :host => @current_company.db_host, :username => @current_company.db_user, :password => @current_company.db_password, :database => @current_company.db_name ) redefine_uploaders_store_dir else redirect_to root_url end end end # CarrierWave def redefine_uploaders_store_dir CarrierWave::Uploader::Base.descendants.each do |d| d.class_eval <<-RUBY, __FILE__, __LINE__+1 def store_dir "uploads/#{@current_company.subdomain}/\#{model.class.to_s.underscore}/\#{mounted_as}/\#{model.id}" end RUBY end end end
config.cache_classes = false
rails g session_migration rake db:migrate
MyApp::Application.config.session_store :active_record_store
# Load the rails application require File.expand_path('../application', __FILE__) # Initialize the rails application MyApp::Application.initialize! ActiveRecord::SessionStore::Session.establish_connection "production"
namespace :db do desc "Migrations for all databases" task :multimigrate => :environment do Company.all.each do |company| company.brands.each do |brand| puts "Run migration for #{company.name} (#{brand.name})" sh "cd #{Rails.root.to_s} && bundle exec rake db:migrate RAILS_ENV=#{brand.db_name}" end end end end
class Brand < ActiveRecord::Base establish_connection "production" belongs_to :company after_save :sync_to_yml validates :name, :db_name, presence: true private def sync_to_yml db_config = YAML.load_file(Rails.root.to_s + '/config/database.yml') db_config[self.db_name] = { 'adapter' => 'postgresql', 'encoding' => 'unicode', 'database' => self.db_name, 'pool' => 5, 'username' => self.company.db_user, 'password' => self.company.db_password.present? ? self.company.db_password : nil } if self.company.db_host != 'localhost' db_config[self.db_name].merge( { 'host' => self.company.db_host, 'port' => self.company.db_port } ) end File.open( Rails.root.to_s + '/config/database.yml', 'w' ) do |out| YAML.dump( db_config, out ) end end end
Source: https://habr.com/ru/post/143761/
All Articles