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