lib/replica.rb in replica-1.0.1 vs lib/replica.rb in replica-1.0.2
- old
+ new
@@ -9,31 +9,34 @@
# Account.with_slave do
# Account.first
# end
# the first account will be found on the slave DB
#
+ # For one-liners you can simply do
+ # Account.with_slave.first
+ #
# this is the same as:
# Account.with_replica(:slave) do
# Account.first
# end
def with_slave(&block)
with_replica(:slave, &block)
end
-
+
# See with_slave
def with_master(&block)
with_replica(nil, &block)
end
def with_slave_if(condition, &block)
condition ? with_slave(&block) : with_master(&block)
end
-
+
def with_slave_unless(condition, &block)
with_slave_if(!condition, &block)
end
-
+
# Name of the connection pool. Used by ConnectionHandler to retrieve the current connection pool.
def connection_pool_name # :nodoc:
replica = current_replica_name
if replica
"#{name}_#{replica}"
@@ -42,83 +45,101 @@
else
superclass.connection_pool_name
end
end
- # Specify which database to use.
+ # Specify which database to use.
#
# Example:
# database.yml
# test_slave:
# adapter: mysql
# ...
#
# Account.with_replica(:slave) { Account.count }
+ # Account.with_replica(:slave).count
#
def with_replica(replica_name, &block)
+ if block_given?
+ with_replica_block(replica_name, &block)
+ else
+ Proxy.new(self, replica_name)
+ end
+ end
+
+ def with_replica_block(replica_name, &block)
old_replica_name = current_replica_name
begin
self.current_replica_name = replica_name
rescue ActiveRecord::AdapterNotSpecified => e
self.current_replica_name = old_replica_name
logger.warn("Failed to establish replica connection: #{e.message} - defaulting to master")
- end
+ end
yield
ensure
self.current_replica_name = old_replica_name
end
private
-
+
def current_replica_name
Thread.current[replica_key]
end
def current_replica_name=(new_replica_name)
Thread.current[replica_key] = new_replica_name
establish_replica_connection(new_replica_name) unless connected_to_replica?
end
-
+
def establish_replica_connection(replica_name)
- name = replica_name ? "#{RAILS_ENV}_#{replica_name}" : RAILS_ENV
- spec = configurations[name]
- raise AdapterNotSpecified.new("No database defined by #{name} in database.yml") if spec.nil?
-
- connection_handler.establish_connection(connection_pool_name, ConnectionSpecification.new(spec, "#{spec['adapter']}_connection"))
+ name = replica_name ? "#{RAILS_ENV}_#{replica_name}" : RAILS_ENV
+ spec = configurations[name]
+ raise AdapterNotSpecified.new("No database defined by #{name} in database.yml") if spec.nil?
+
+ connection_handler.establish_connection(connection_pool_name, ConnectionSpecification.new(spec, "#{spec['adapter']}_connection"))
end
-
+
def connected_to_replica?
connection_handler.connection_pools.has_key?(connection_pool_name)
end
-
+
def replica_key
@replica_key ||= "#{name}_replica"
end
-
+
+ class Proxy
+ def initialize(target, replica)
+ @target = target
+ @replica = replica
+ end
+
+ def method_missing(method, *args)
+ @target.with_replica_block(@replica) { @target.send(method, *args) }
+ end
+ end
end
end
Base.extend(Base::Replica)
-
+
# The only difference here is that we use klass.connection_pool_name
# instead of klass.name as the pool key
module ConnectionAdapters # :nodoc:
class ConnectionHandler # :nodoc:
-
+
def retrieve_connection_pool(klass)
pool = @connection_pools[klass.connection_pool_name]
return pool if pool
return nil if ActiveRecord::Base == klass
retrieve_connection_pool klass.superclass
end
-
+
def remove_connection(klass)
- pool = @connection_pools[klass.connection_pool_name]
- @connection_pools.delete_if { |key, value| value == pool }
- pool.disconnect! if pool
- pool.spec.config if pool
- end
-
+ pool = @connection_pools[klass.connection_pool_name]
+ @connection_pools.delete_if { |key, value| value == pool }
+ pool.disconnect! if pool
+ pool.spec.config if pool
+ end
+
end
end
end
-