lib/connection_manager/using.rb in connection_manager-1.0.3 vs lib/connection_manager/using.rb in connection_manager-1.0.4
- old
+ new
@@ -1,89 +1,54 @@
require 'active_support/core_ext/module/delegation'
module ConnectionManager
module Using
- module ClassMethods
+ module Relation
- # We use dup here because its just too tricky to make sure we override
- # all the methods necessary when using a child class of the model. This
- # action is lazy and the created sub is named to a constant so we only
- # have to do it once.
- def fetch_duplicate_class(connection_class_name)
- begin
- return "#{self.name}::#{connection_class_name}Dup".constantize
- rescue NameError
- return build_dup_class(connection_class_name)
- end
+ # Specify connection class to used for query.For
+ # example:
+ #
+ # users = User.using(MySlaveConnection).first
+ def using(connection_class_name)
+ @klass = ConnectionManager::Using::Proxy.new(@klass,connection_class_name)
+ self
end
+ end
- private
- # Modifies the dup class to use the connection class connection.
- # We want to use the current class table name, but the connection
- # class database as the prefix, useful when shards but normally
- # should be the same. We also want the superclass method to
- # return the connection class as AR sometimes uses the the superclass
- # connection
- def build_dup_class(connection_class_name)
- use_database(self.current_database_name) # make sure we are consistent from super to dup
- con_class = connection_class_name.constantize
- db_name = con_class.current_database_name
- dup_klass = dup
- dup_klass.class_eval <<-STR
- self.use_database('#{db_name}',{:table_name => '#{table_name}'})
- class << self
- def model_name
- #{self.name}.model_name
- end
- def connection_class
- #{connection_class_name}
- end
- def connection
- connection_class.connection
- end
- def superclass
- connection_class
- end
- end
- STR
+ class Proxy
+ attr_accessor :klass, :connection_class
+
+ def initialize(klass,connection_class)
+ @klass = klass # the @klass insance from an ActiveRecord::Relation
+ @connection_class = (connection_class.is_a?(String) ? connection_class.constantize : connection_class)
+ end
- self.const_set("#{connection_class_name}Dup", dup_klass)
- "#{self.name}::#{connection_class_name}Dup".constantize
+ # Use the connection from the connection class
+ def connection
+ ConnectionManager.logger.info "Using proxy connection: #{@connection_class.name} for #{@klass.name}" if ConnectionManager.logger
+ @connection_class.connection
end
- end
- # Instance method for casting to a duplication class
- def using(connection_class)
- becomes(self.class.using(connection_class).klass)
- end
+ # Make sure we return the @klass superclass,
+ # which used through the query building code in AR
+ def superclass
+ @klass.superclass
+ end
- def self.included(host_class)
- host_class.extend(ClassMethods)
- end
- end
-end
+ # Pass all methods to @klass, this ensures objects
+ # build from the query are the correct class and
+ # any settings in the model like table_name_prefix
+ # are used.
+ def method_missing(name, *args, &blk)
+ @klass.send(name, *args,&blk)
+ end
-module ActiveRecord
- # = Active Record Relation
- class Relation
- if ActiveRecord::VERSION::MAJOR == 4
- def using(connection_class_name)
- d = @klass.fetch_duplicate_class(connection_class_name)
- self.instance_variable_set(:@arel_table, d.arel_table)
- self.instance_variable_set(:@klass, d)
- self
+ def respond_to?(method_name, include_private = false)
+ @klass.respond_to?(method_name) || super
end
- else
- def using(connection_class_name)
- d = @klass.fetch_duplicate_class(connection_class_name)
- rel = clone
- rel.instance_variable_set(:@arel_table, d.arel_table)
- rel.instance_variable_set(:@klass, d)
- rel
- end
end
end
end
-
+ActiveRecord::Relation.send(:include,ConnectionManager::Using::Relation)
module ActiveRecord
class Base
class << self
delegate :using, :to => (ActiveRecord::VERSION::MAJOR == 4 ? :all : :scoped)
end