Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added the ability to specify the slave database.

Calling or not-calling ConnectionProxy.setup! will work the same
if no master or slave connection specified for the current environment.

I also removed trailing spaces and added tests.
  • Loading branch information...
commit 1bd18ef778bb54f7ef3796e0ebd9a21766ab4ab7 1 parent 176aa0e
Scott Steadman authored
View
18 README
@@ -8,7 +8,12 @@ to a master database, and the rest to the slave database.
The ActiveReload::MasterDatabase model uses a 'master_database' setting that
can either be defined for all of your environments, or for each environment as
-a nested declaration:
+a nested declaration.
+
+The ActiveReload::SlaveDatabase model uses a 'slave_database' setting that
+can only be defined per environment.
+
+Example declarations:
# config/database.yml
login: &login
@@ -33,6 +38,15 @@ a nested declaration:
host: master-db-server.local
<<: *login
+ qa:
+ database: qa_master_database_name
+ host: qa-master
+ <<: *login
+ slave_database:
+ database: qa_slave_database_name
+ host: qa-slave
+ <<: *login
+
development: # Does not use masochism
database: development_database_name
<<: *login
@@ -81,4 +95,4 @@ class RandomController < ApplicationController
around_filter ActiveReload::MasterFilter, :only => [:show, :edit, :update]
...
-end
+end
View
44 lib/active_reload/connection_proxy.rb
@@ -1,7 +1,15 @@
module ActiveReload
class MasterDatabase < ActiveRecord::Base
self.abstract_class = true
- establish_connection configurations[Rails.env]['master_database'] || :master_database
+ establish_connection configurations[Rails.env]['master_database'] || configurations['master_database'] || Rails.env
+ end
+
+ class SlaveDatabase < ActiveRecord::Base
+ self.abstract_class = true
+ def self.name
+ ActiveRecord::Base.name
+ end
+ establish_connection configurations[Rails.env]['slave_database'] || Rails.env
end
class ConnectionProxy
@@ -10,13 +18,21 @@ def initialize(master, slave)
@master = master.connection
@current = @slave
end
-
+
attr_accessor :slave, :master
def self.setup!
- setup_for ActiveReload::MasterDatabase
+ if slave_defined?
+ setup_for ActiveReload::MasterDatabase, ActiveReload::SlaveDatabase
+ else
+ setup_for ActiveReload::MasterDatabase
+ end
+ end
+
+ def self.slave_defined?
+ ActiveRecord::Base.configurations[Rails.env]['slave_database']
end
-
+
def self.setup_for(master, slave = nil)
slave ||= ActiveRecord::Base
slave.send :include, ActiveRecordConnectionMethods
@@ -33,22 +49,22 @@ def with_master
def set_to_master!
return if @current == @master
-
+
logger.info "Switching to Master"
@current = @master
end
-
+
def set_to_slave!
return if @current == @slave
-
+
logger.info "Switching to Slave"
@current = @slave
end
-
- delegate :insert, :update, :delete, :create_table, :rename_table, :drop_table, :add_column, :remove_column,
+
+ delegate :insert, :update, :delete, :create_table, :rename_table, :drop_table, :add_column, :remove_column,
:change_column, :change_column_default, :rename_column, :add_index, :remove_index, :initialize_schema_information,
:dump_schema_information, :execute, :to => :master
-
+
def transaction(start_db_transaction = true, &block)
with_master { @current.transaction(start_db_transaction, &block) }
end
@@ -57,12 +73,12 @@ def method_missing(method, *args, &block)
@current.send(method, *args, &block)
end
end
-
+
module ActiveRecordConnectionMethods
def self.included(base)
base.alias_method_chain :reload, :master
end
-
+
def reload_with_master(*args, &block)
if connection.class.name == "ActiveReload::ConnectionProxy"
connection.with_master { reload_without_master }
@@ -79,7 +95,7 @@ module ObserverExtensions
def self.included(base)
base.alias_method_chain :update, :masterdb
end
-
+
# Send observed_method(object) if the method exists.
def update_with_masterdb(observed_method, object) #:nodoc:
if object.class.connection.respond_to?(:with_master)
@@ -91,4 +107,4 @@ def update_with_masterdb(observed_method, object) #:nodoc:
end
end
end
-end
+end
View
104 test/connection_proxy_test.rb
@@ -0,0 +1,104 @@
+require File.dirname(__FILE__) + '/../../../../config/environment'
+require 'test/unit'
+require 'fileutils'
+require 'pp'
+
+module ActiveReload
+ class ConnectionProxyTest < Test::Unit::TestCase
+
+ MASTER = 'db/masochism_master.sqlite3'
+ SLAVE = 'db/masochism_slave.sqlite3'
+
+ def teardown
+ ActiveRecord::Base.remove_connection
+ FileUtils.rm_f(Rails.root + '/' + MASTER)
+ FileUtils.rm_f(Rails.root + '/' + SLAVE)
+ end
+
+ def test_slave_defined_returns_false_when_slave_not_defined
+ ActiveRecord::Base.configurations = default_config
+ assert_nil ActiveReload::ConnectionProxy.slave_defined?, 'Slave should not be defined'
+ end
+
+ def test_slave_defined_returns_true_when_slave_defined
+ ActiveRecord::Base.configurations = slave_inside_config
+ assert_not_nil ActiveReload::ConnectionProxy.slave_defined?, 'Slave should be defined'
+ end
+
+ def test_default
+ ActiveRecord::Base.configurations = default_config
+ reload
+ ActiveReload::ConnectionProxy.setup!
+
+ ActiveRecord::Base.connection.master.execute('CREATE TABLE foo (id int)')
+ assert_equal ['foo'], ActiveRecord::Base.connection.tables, 'Master and Slave should be the same database'
+ assert_equal ['foo'], ActiveRecord::Base.connection.slave.tables, 'Master and Slave should be the same database'
+ end
+
+ def test_master_database_outside_environment
+ ActiveRecord::Base.configurations = master_outside_config
+ reload
+ ActiveReload::ConnectionProxy.setup!
+
+ ActiveRecord::Base.connection.master.execute('CREATE TABLE foo (id int)')
+ assert_equal [], ActiveRecord::Base.connection.tables, 'Master and Slave should be different databases'
+ assert_equal [], ActiveRecord::Base.connection.slave.tables, 'Master and Slave should be different databases'
+ end
+
+ def test_master_database_within_environment
+ ActiveRecord::Base.configurations = master_inside_config
+ reload
+ ActiveReload::ConnectionProxy.setup!
+
+ ActiveRecord::Base.connection.master.execute('CREATE TABLE foo (id int)')
+ assert_equal [], ActiveRecord::Base.connection.tables, 'Master and Slave should be different databases'
+ assert_equal [], ActiveRecord::Base.connection.slave.tables, 'Master and Slave should be different databases'
+ end
+
+ def test_slave_database_within_environment
+ ActiveRecord::Base.configurations = slave_inside_config
+ reload
+ ActiveReload::ConnectionProxy.setup!
+
+ ActiveRecord::Base.connection.master.execute('CREATE TABLE foo (id int)')
+ assert_equal [], ActiveRecord::Base.connection.tables, 'Master and Slave should be different databases'
+ assert_equal [], ActiveRecord::Base.connection.slave.tables, 'Master and Slave should be different databases'
+ end
+
+ private
+
+ def reload
+ # force establish_connection calls to be re-executed
+ load File.dirname(__FILE__)+'/../lib/active_reload/connection_proxy.rb'
+ end
+
+ def default_config
+ {Rails.env => {'adapter' => 'sqlite3', 'database' => MASTER}}
+ end
+
+ def master_outside_config
+ {
+ Rails.env => {'adapter' => 'sqlite3', 'database' => SLAVE},
+ 'master_database' => {'adapter' => 'sqlite3', 'database' => MASTER}
+ }
+ end
+
+ def master_inside_config
+ {
+ Rails.env => {'adapter' => 'sqlite3', 'database' => SLAVE,
+ 'master_database' => {'adapter' => 'sqlite3', 'database' => MASTER}
+ }
+ }
+ end
+
+ def slave_inside_config
+ {
+ Rails.env => {'adapter' => 'sqlite3', 'database' => MASTER,
+ 'slave_database' => {'adapter' => 'sqlite3', 'database' => SLAVE}
+ }
+ }
+ end
+
+
+ end # class ConnectionProxyTest
+end # module ActiveReload
Please sign in to comment.
Something went wrong with that request. Please try again.