Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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
18 README
@@ -8,7 +8,12 @@ to a master database, and the rest to the slave database.
8 8
9 9 The ActiveReload::MasterDatabase model uses a 'master_database' setting that
10 10 can either be defined for all of your environments, or for each environment as
11   -a nested declaration:
  11 +a nested declaration.
  12 +
  13 +The ActiveReload::SlaveDatabase model uses a 'slave_database' setting that
  14 +can only be defined per environment.
  15 +
  16 +Example declarations:
12 17
13 18 # config/database.yml
14 19 login: &login
@@ -33,6 +38,15 @@ a nested declaration:
33 38 host: master-db-server.local
34 39 <<: *login
35 40
  41 + qa:
  42 + database: qa_master_database_name
  43 + host: qa-master
  44 + <<: *login
  45 + slave_database:
  46 + database: qa_slave_database_name
  47 + host: qa-slave
  48 + <<: *login
  49 +
36 50 development: # Does not use masochism
37 51 database: development_database_name
38 52 <<: *login
@@ -81,4 +95,4 @@ class RandomController < ApplicationController
81 95 around_filter ActiveReload::MasterFilter, :only => [:show, :edit, :update]
82 96
83 97 ...
84   -end
  98 +end
44 lib/active_reload/connection_proxy.rb
... ... @@ -1,7 +1,15 @@
1 1 module ActiveReload
2 2 class MasterDatabase < ActiveRecord::Base
3 3 self.abstract_class = true
4   - establish_connection configurations[Rails.env]['master_database'] || :master_database
  4 + establish_connection configurations[Rails.env]['master_database'] || configurations['master_database'] || Rails.env
  5 + end
  6 +
  7 + class SlaveDatabase < ActiveRecord::Base
  8 + self.abstract_class = true
  9 + def self.name
  10 + ActiveRecord::Base.name
  11 + end
  12 + establish_connection configurations[Rails.env]['slave_database'] || Rails.env
5 13 end
6 14
7 15 class ConnectionProxy
@@ -10,13 +18,21 @@ def initialize(master, slave)
10 18 @master = master.connection
11 19 @current = @slave
12 20 end
13   -
  21 +
14 22 attr_accessor :slave, :master
15 23
16 24 def self.setup!
17   - setup_for ActiveReload::MasterDatabase
  25 + if slave_defined?
  26 + setup_for ActiveReload::MasterDatabase, ActiveReload::SlaveDatabase
  27 + else
  28 + setup_for ActiveReload::MasterDatabase
  29 + end
  30 + end
  31 +
  32 + def self.slave_defined?
  33 + ActiveRecord::Base.configurations[Rails.env]['slave_database']
18 34 end
19   -
  35 +
20 36 def self.setup_for(master, slave = nil)
21 37 slave ||= ActiveRecord::Base
22 38 slave.send :include, ActiveRecordConnectionMethods
@@ -33,22 +49,22 @@ def with_master
33 49
34 50 def set_to_master!
35 51 return if @current == @master
36   -
  52 +
37 53 logger.info "Switching to Master"
38 54 @current = @master
39 55 end
40   -
  56 +
41 57 def set_to_slave!
42 58 return if @current == @slave
43   -
  59 +
44 60 logger.info "Switching to Slave"
45 61 @current = @slave
46 62 end
47   -
48   - delegate :insert, :update, :delete, :create_table, :rename_table, :drop_table, :add_column, :remove_column,
  63 +
  64 + delegate :insert, :update, :delete, :create_table, :rename_table, :drop_table, :add_column, :remove_column,
49 65 :change_column, :change_column_default, :rename_column, :add_index, :remove_index, :initialize_schema_information,
50 66 :dump_schema_information, :execute, :to => :master
51   -
  67 +
52 68 def transaction(start_db_transaction = true, &block)
53 69 with_master { @current.transaction(start_db_transaction, &block) }
54 70 end
@@ -57,12 +73,12 @@ def method_missing(method, *args, &block)
57 73 @current.send(method, *args, &block)
58 74 end
59 75 end
60   -
  76 +
61 77 module ActiveRecordConnectionMethods
62 78 def self.included(base)
63 79 base.alias_method_chain :reload, :master
64 80 end
65   -
  81 +
66 82 def reload_with_master(*args, &block)
67 83 if connection.class.name == "ActiveReload::ConnectionProxy"
68 84 connection.with_master { reload_without_master }
@@ -79,7 +95,7 @@ module ObserverExtensions
79 95 def self.included(base)
80 96 base.alias_method_chain :update, :masterdb
81 97 end
82   -
  98 +
83 99 # Send observed_method(object) if the method exists.
84 100 def update_with_masterdb(observed_method, object) #:nodoc:
85 101 if object.class.connection.respond_to?(:with_master)
@@ -91,4 +107,4 @@ def update_with_masterdb(observed_method, object) #:nodoc:
91 107 end
92 108 end
93 109 end
94   -end
  110 +end
104 test/connection_proxy_test.rb
... ... @@ -0,0 +1,104 @@
  1 +require File.dirname(__FILE__) + '/../../../../config/environment'
  2 +require 'test/unit'
  3 +require 'fileutils'
  4 +require 'pp'
  5 +
  6 +module ActiveReload
  7 + class ConnectionProxyTest < Test::Unit::TestCase
  8 +
  9 + MASTER = 'db/masochism_master.sqlite3'
  10 + SLAVE = 'db/masochism_slave.sqlite3'
  11 +
  12 + def teardown
  13 + ActiveRecord::Base.remove_connection
  14 + FileUtils.rm_f(Rails.root + '/' + MASTER)
  15 + FileUtils.rm_f(Rails.root + '/' + SLAVE)
  16 + end
  17 +
  18 + def test_slave_defined_returns_false_when_slave_not_defined
  19 + ActiveRecord::Base.configurations = default_config
  20 + assert_nil ActiveReload::ConnectionProxy.slave_defined?, 'Slave should not be defined'
  21 + end
  22 +
  23 + def test_slave_defined_returns_true_when_slave_defined
  24 + ActiveRecord::Base.configurations = slave_inside_config
  25 + assert_not_nil ActiveReload::ConnectionProxy.slave_defined?, 'Slave should be defined'
  26 + end
  27 +
  28 + def test_default
  29 + ActiveRecord::Base.configurations = default_config
  30 + reload
  31 + ActiveReload::ConnectionProxy.setup!
  32 +
  33 + ActiveRecord::Base.connection.master.execute('CREATE TABLE foo (id int)')
  34 + assert_equal ['foo'], ActiveRecord::Base.connection.tables, 'Master and Slave should be the same database'
  35 + assert_equal ['foo'], ActiveRecord::Base.connection.slave.tables, 'Master and Slave should be the same database'
  36 + end
  37 +
  38 + def test_master_database_outside_environment
  39 + ActiveRecord::Base.configurations = master_outside_config
  40 + reload
  41 + ActiveReload::ConnectionProxy.setup!
  42 +
  43 + ActiveRecord::Base.connection.master.execute('CREATE TABLE foo (id int)')
  44 + assert_equal [], ActiveRecord::Base.connection.tables, 'Master and Slave should be different databases'
  45 + assert_equal [], ActiveRecord::Base.connection.slave.tables, 'Master and Slave should be different databases'
  46 + end
  47 +
  48 + def test_master_database_within_environment
  49 + ActiveRecord::Base.configurations = master_inside_config
  50 + reload
  51 + ActiveReload::ConnectionProxy.setup!
  52 +
  53 + ActiveRecord::Base.connection.master.execute('CREATE TABLE foo (id int)')
  54 + assert_equal [], ActiveRecord::Base.connection.tables, 'Master and Slave should be different databases'
  55 + assert_equal [], ActiveRecord::Base.connection.slave.tables, 'Master and Slave should be different databases'
  56 + end
  57 +
  58 + def test_slave_database_within_environment
  59 + ActiveRecord::Base.configurations = slave_inside_config
  60 + reload
  61 + ActiveReload::ConnectionProxy.setup!
  62 +
  63 + ActiveRecord::Base.connection.master.execute('CREATE TABLE foo (id int)')
  64 + assert_equal [], ActiveRecord::Base.connection.tables, 'Master and Slave should be different databases'
  65 + assert_equal [], ActiveRecord::Base.connection.slave.tables, 'Master and Slave should be different databases'
  66 + end
  67 +
  68 + private
  69 +
  70 + def reload
  71 + # force establish_connection calls to be re-executed
  72 + load File.dirname(__FILE__)+'/../lib/active_reload/connection_proxy.rb'
  73 + end
  74 +
  75 + def default_config
  76 + {Rails.env => {'adapter' => 'sqlite3', 'database' => MASTER}}
  77 + end
  78 +
  79 + def master_outside_config
  80 + {
  81 + Rails.env => {'adapter' => 'sqlite3', 'database' => SLAVE},
  82 + 'master_database' => {'adapter' => 'sqlite3', 'database' => MASTER}
  83 + }
  84 + end
  85 +
  86 + def master_inside_config
  87 + {
  88 + Rails.env => {'adapter' => 'sqlite3', 'database' => SLAVE,
  89 + 'master_database' => {'adapter' => 'sqlite3', 'database' => MASTER}
  90 + }
  91 + }
  92 + end
  93 +
  94 + def slave_inside_config
  95 + {
  96 + Rails.env => {'adapter' => 'sqlite3', 'database' => MASTER,
  97 + 'slave_database' => {'adapter' => 'sqlite3', 'database' => SLAVE}
  98 + }
  99 + }
  100 + end
  101 +
  102 +
  103 + end # class ConnectionProxyTest
  104 +end # module ActiveReload

0 comments on commit 1bd18ef

Please sign in to comment.
Something went wrong with that request. Please try again.