module DbCharmer module ActiveRecord module DbMagic def db_magic(opt = {}) # Make sure we could use our connections management here hijack_connection! # Should requested connections exist in the config? should_exist = opt.has_key?(:should_exist) ? opt[:should_exist] : DbCharmer.connections_should_exist? # Main connection management setup_connection_magic(opt[:connection], should_exist) # Set up slaves pool opt[:slaves] ||= [] opt[:slaves] = [ opt[:slaves] ].flatten opt[:slaves] << opt[:slave] if opt[:slave] # Forced reads are enabled for all models by default, could be disabled by the user forced_slave_reads = opt.has_key?(:force_slave_reads) ? opt[:force_slave_reads] : true # Setup all the slaves related magic if needed setup_slaves_magic(opt[:slaves], forced_slave_reads, should_exist) # Setup inheritance magic setup_children_magic(opt) # Setup sharding if needed if opt[:sharded] raise ArgumentError, "Can't use sharding on a model with slaves!" if opt[:slaves].any? setup_sharding_magic(opt[:sharded]) end end private def setup_children_magic(opt) self.db_charmer_opts = opt.clone unless self.respond_to?(:inherited_with_db_magic) class << self def inherited_with_db_magic(child) o = inherited_without_db_magic(child) child.db_magic(self.db_charmer_opts) o end alias_method_chain :inherited, :db_magic end end end def setup_sharding_magic(config) # Add sharding-specific methods self.extend(DbCharmer::ActiveRecord::Sharding) # Get configuration name = config[:sharded_connection] or raise ArgumentError, "No :sharded_connection!" # Assign sharded connection self.sharded_connection = DbCharmer::Sharding.sharded_connection(name) # Setup model default connection setup_connection_magic(sharded_connection.default_connection) end def setup_connection_magic(conn, should_exist = true) conn_proxy = coerce_to_connection_proxy(conn, should_exist) self.db_charmer_default_connection = conn_proxy switch_connection_to(conn_proxy, should_exist) end def setup_slaves_magic(slaves, force_slave_reads, should_exist = true) self.db_charmer_force_slave_reads = force_slave_reads # Initialize the slave connections list self.db_charmer_slaves = slaves.collect do |slave| coerce_to_connection_proxy(slave, should_exist) end return if db_charmer_slaves.empty? # Enable on_slave/on_master methods self.extend(DbCharmer::ActiveRecord::MultiDbProxy::MasterSlaveClassMethods) # Enable automatic master/slave queries routing (we have specialized versions on those modules for rails2/3) self.extend(DbCharmer::ActiveRecord::MasterSlaveRouting::ClassMethods) self.send(:include, DbCharmer::ActiveRecord::MasterSlaveRouting::InstanceMethods) end end end end