magic_multi_connections 1.0.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. data/CHANGELOG.txt +0 -0
  2. data/History.txt +0 -0
  3. data/Manifest.txt +43 -32
  4. data/README.txt +0 -0
  5. data/Rakefile +21 -15
  6. data/lib/ext_active_record/association_extensions.rb +90 -0
  7. data/lib/ext_active_record/connection_specification.rb +0 -0
  8. data/lib/magic_multi_connections.rb +22 -21
  9. data/lib/magic_multi_connections/connected.rb +91 -29
  10. data/lib/magic_multi_connections/module.rb +27 -26
  11. data/lib/magic_multi_connections/version.rb +9 -9
  12. data/scripts/txt2html +0 -0
  13. data/scripts/txt2js +1 -1
  14. data/setup.rb +0 -0
  15. data/test/connections/native_mysql/connection.rb +24 -0
  16. data/test/connections/native_postgresql/connection.rb +0 -0
  17. data/test/fixtures/address.rb +3 -0
  18. data/test/fixtures/addresses.yml +4 -0
  19. data/test/fixtures/assignment.rb +7 -0
  20. data/test/fixtures/classified.rb +5 -0
  21. data/test/fixtures/contact_repository.rb +2 -2
  22. data/test/fixtures/db_definitions/mysql.sql +19 -0
  23. data/test/fixtures/db_definitions/postgresql.sql +7 -1
  24. data/test/fixtures/habit.rb +3 -0
  25. data/test/fixtures/paycheck.rb +3 -0
  26. data/test/fixtures/people.yml +0 -0
  27. data/test/fixtures/person.rb +3 -1
  28. data/test/fixtures/soldier.rb +8 -0
  29. data/test/test_helper.rb +71 -71
  30. data/test/test_magic_multi_connections.rb +27 -26
  31. data/test/test_mmc_associations.rb +46 -0
  32. data/test/test_parent_module.rb +0 -0
  33. data/test/test_preexisting_module.rb +0 -0
  34. data/website/index.html +354 -340
  35. data/website/index.txt +286 -223
  36. data/website/javascripts/rounded_corners_lite.inc.js +0 -0
  37. data/website/stylesheets/screen.css +0 -0
  38. data/website/template.js +0 -0
  39. data/website/template.rhtml +0 -0
  40. data/website/version-raw.js +2 -2
  41. data/website/version-raw.txt +1 -1
  42. data/website/version.js +1 -1
  43. data/website/version.txt +0 -0
  44. metadata +63 -37
@@ -1,9 +1,9 @@
1
- module MagicMultiConnection #:nodoc:
2
- module VERSION #:nodoc:
3
- MAJOR = 1
4
- MINOR = 0
5
- TINY = 0
6
-
7
- STRING = [MAJOR, MINOR, TINY].join('.')
8
- end
9
- end
1
+ module MagicMultiConnection #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 1
4
+ MINOR = 2
5
+ TINY = 1
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
File without changes
@@ -8,7 +8,7 @@ require 'active_support'
8
8
  require File.dirname(__FILE__) + '/../lib/magic_multi_connections/version.rb'
9
9
 
10
10
  version = MagicMultiConnection::VERSION::STRING
11
- download = 'http://rubyforge.org/projects/compositekeys'
11
+ download = 'http://rubyforge.org/projects/magicmodels'
12
12
 
13
13
  class Fixnum
14
14
  def ordinal
data/setup.rb CHANGED
File without changes
@@ -0,0 +1,24 @@
1
+ print "Using native MySQL\n"
2
+ require 'logger'
3
+
4
+ ActiveRecord::Base.logger = Logger.new("debug.log")
5
+
6
+ db_connection_options = {
7
+ :adapter => "mysql",
8
+ :encoding => "utf8",
9
+ :database => 'magic_multi_connections_unittest',
10
+ :username => "ruby",
11
+ :password => "ruby"
12
+ }
13
+
14
+ db_extra_connection_options = {
15
+ :adapter => "mysql",
16
+ :encoding => "utf8",
17
+ :database => 'magic_multi_connections_extra_unittest',
18
+ :username => "ruby",
19
+ :password => "ruby"
20
+ }
21
+
22
+
23
+ ActiveRecord::Base.configurations = { 'production' => db_connection_options, 'contact_repo' => db_extra_connection_options }
24
+ ActiveRecord::Base.establish_connection(:production)
@@ -0,0 +1,3 @@
1
+ class Address < ActiveRecord::Base
2
+ belongs_to :person
3
+ end
@@ -0,0 +1,4 @@
1
+ first:
2
+ id: 1
3
+ person_id: 1
4
+ address: Springfield
@@ -0,0 +1,7 @@
1
+ module Army
2
+
3
+ class Assignment < ActiveRecord::Base
4
+ belongs_to :soldier
5
+ end
6
+
7
+ end
@@ -0,0 +1,5 @@
1
+ module Army
2
+ module Classified
3
+ establish_connection :contact_repo
4
+ end
5
+ end
@@ -1,3 +1,3 @@
1
- module ContactRepository
2
- establish_connection :contact_repo
1
+ module ContactRepository
2
+ establish_connection :contact_repo, false
3
3
  end
@@ -0,0 +1,19 @@
1
+ DROP TABLE IF EXISTS people;
2
+ CREATE TABLE people (
3
+ id INT(11) AUTO_INCREMENT PRIMARY KEY,
4
+ name VARCHAR(255) NULL,
5
+ email VARCHAR(255) NULL,
6
+ age INT(11) NULL
7
+ );
8
+ DROP TABLE IF EXISTS addresses;
9
+ CREATE TABLE addresses (
10
+ id INT(11) AUTO_INCREMENT PRIMARY KEY,
11
+ person_id INT(11) NULL,
12
+ address VARCHAR(255) NULL
13
+ );
14
+ DROP TABLE IF EXISTS habits;
15
+ CREATE TABLE habits (
16
+ id INT(11) AUTO_INCREMENT PRIMARY KEY,
17
+ person_id INT(11) NULL,
18
+ description VARCHAR(255) NULL
19
+ );
@@ -4,4 +4,10 @@ CREATE TABLE "people" (
4
4
  "email" varchar(255),
5
5
  "age" int,
6
6
  PRIMARY KEY ("id")
7
- );
7
+ );
8
+ CREATE TABLE "addresses" (
9
+ "id" SERIAL,
10
+ "person_id" int,
11
+ "address" varchar(255),
12
+ PRIMARY KEY ("id")
13
+ );
@@ -0,0 +1,3 @@
1
+ class Habit < ActiveRecord::Base
2
+ belongs_to :person, :mirror_db_connection => true
3
+ end
@@ -0,0 +1,3 @@
1
+ class Paycheck < ActiveRecord::Base
2
+ belongs_to :soldier
3
+ end
File without changes
@@ -1,2 +1,4 @@
1
- class Person < ActiveRecord::Base
1
+ class Person < ActiveRecord::Base
2
+ has_many :addresses
3
+ has_many :habits, :mirror_db_connection => true
2
4
  end
@@ -0,0 +1,8 @@
1
+ module Army
2
+
3
+ class Soldier < ActiveRecord::Base
4
+ has_many :assignments
5
+ has_many :paychecks
6
+ has_many :citations, :class_name => "Justice::Citation"
7
+ end
8
+ end
@@ -1,71 +1,71 @@
1
- require 'test/unit'
2
- require 'rubygems'
3
- require 'active_record'
4
- require 'active_record/fixtures'
5
-
6
- begin
7
- require 'connection'
8
- rescue MissingSourceFile => e
9
- # required for tests not run via test_#{adapter} rake tests, e.g. autotest
10
- adapter = 'postgresql' #'sqlite'
11
- require "#{File.dirname(__FILE__)}/connections/native_#{adapter}/connection"
12
- end
13
-
14
- require File.dirname(__FILE__) + '/../lib/magic_multi_connections'
15
-
16
-
17
- models = %w[person contact_repository]
18
- models.each { |model| require File.join(File.dirname(__FILE__), 'fixtures', model) }
19
-
20
- class Test::Unit::TestCase #:nodoc:
21
- self.fixture_path = File.dirname(__FILE__) + "/fixtures/"
22
- self.use_instantiated_fixtures = false
23
- self.use_transactional_fixtures = true #(ENV['AR_NO_TX_FIXTURES'] != "yes")
24
-
25
- def create_fixtures(*table_names, &block)
26
- Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures/", table_names, {}, &block)
27
- end
28
-
29
- def assert_date_from_db(expected, actual, message = nil)
30
- # SQL Server doesn't have a separate column type just for dates,
31
- # so the time is in the string and incorrectly formatted
32
- if current_adapter?(:SQLServerAdapter)
33
- assert_equal expected.strftime("%Y/%m/%d 00:00:00"), actual.strftime("%Y/%m/%d 00:00:00")
34
- elsif current_adapter?(:SybaseAdapter)
35
- assert_equal expected.to_s, actual.to_date.to_s, message
36
- else
37
- assert_equal expected.to_s, actual.to_s, message
38
- end
39
- end
40
-
41
- def assert_queries(num = 1)
42
- ActiveRecord::Base.connection.class.class_eval do
43
- self.query_count = 0
44
- alias_method :execute, :execute_with_query_counting
45
- end
46
- yield
47
- ensure
48
- ActiveRecord::Base.connection.class.class_eval do
49
- alias_method :execute, :execute_without_query_counting
50
- end
51
- assert_equal num, ActiveRecord::Base.connection.query_count, "#{ActiveRecord::Base.connection.query_count} instead of #{num} queries were executed."
52
- end
53
-
54
- def assert_no_queries(&block)
55
- assert_queries(0, &block)
56
- end
57
- end
58
-
59
- def current_adapter?(type)
60
- ActiveRecord::ConnectionAdapters.const_defined?(type) &&
61
- ActiveRecord::Base.connection.instance_of?(ActiveRecord::ConnectionAdapters.const_get(type))
62
- end
63
-
64
- ActiveRecord::Base.connection.class.class_eval do
65
- cattr_accessor :query_count
66
- alias_method :execute_without_query_counting, :execute
67
- def execute_with_query_counting(sql, name = nil)
68
- self.query_count += 1
69
- execute_without_query_counting(sql, name)
70
- end
71
- end
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'active_record'
4
+ require 'active_record/fixtures'
5
+
6
+ begin
7
+ require 'connection'
8
+ rescue MissingSourceFile => e
9
+ # required for tests not run via test_#{adapter} rake tests, e.g. autotest
10
+ adapter = 'mysql' #'sqlite', 'mysql'
11
+ require "#{File.dirname(__FILE__)}/connections/native_#{adapter}/connection"
12
+ end
13
+
14
+ require File.dirname(__FILE__) + '/../lib/magic_multi_connections'
15
+
16
+
17
+ models = %w[person contact_repository address soldier paycheck assignment classified habit citation]
18
+ models.each { |model| require File.join(File.dirname(__FILE__), 'fixtures', model) }
19
+
20
+ class Test::Unit::TestCase #:nodoc:
21
+ self.fixture_path = File.dirname(__FILE__) + "/fixtures/"
22
+ self.use_instantiated_fixtures = false
23
+ self.use_transactional_fixtures = true #(ENV['AR_NO_TX_FIXTURES'] != "yes")
24
+
25
+ def create_fixtures(*table_names, &block)
26
+ Fixtures.create_fixtures(File.dirname(__FILE__) + "/fixtures/", table_names, {}, &block)
27
+ end
28
+
29
+ def assert_date_from_db(expected, actual, message = nil)
30
+ # SQL Server doesn't have a separate column type just for dates,
31
+ # so the time is in the string and incorrectly formatted
32
+ if current_adapter?(:SQLServerAdapter)
33
+ assert_equal expected.strftime("%Y/%m/%d 00:00:00"), actual.strftime("%Y/%m/%d 00:00:00")
34
+ elsif current_adapter?(:SybaseAdapter)
35
+ assert_equal expected.to_s, actual.to_date.to_s, message
36
+ else
37
+ assert_equal expected.to_s, actual.to_s, message
38
+ end
39
+ end
40
+
41
+ def assert_queries(num = 1)
42
+ ActiveRecord::Base.connection.class.class_eval do
43
+ self.query_count = 0
44
+ alias_method :execute, :execute_with_query_counting
45
+ end
46
+ yield
47
+ ensure
48
+ ActiveRecord::Base.connection.class.class_eval do
49
+ alias_method :execute, :execute_without_query_counting
50
+ end
51
+ assert_equal num, ActiveRecord::Base.connection.query_count, "#{ActiveRecord::Base.connection.query_count} instead of #{num} queries were executed."
52
+ end
53
+
54
+ def assert_no_queries(&block)
55
+ assert_queries(0, &block)
56
+ end
57
+ end
58
+
59
+ def current_adapter?(type)
60
+ ActiveRecord::ConnectionAdapters.const_defined?(type) &&
61
+ ActiveRecord::Base.connection.instance_of?(ActiveRecord::ConnectionAdapters.const_get(type))
62
+ end
63
+
64
+ ActiveRecord::Base.connection.class.class_eval do
65
+ cattr_accessor :query_count
66
+ alias_method :execute_without_query_counting, :execute
67
+ def execute_with_query_counting(sql, name = nil)
68
+ self.query_count += 1
69
+ execute_without_query_counting(sql, name)
70
+ end
71
+ end
@@ -1,26 +1,27 @@
1
- require File.dirname(__FILE__) + '/test_helper.rb'
2
-
3
- module NormalModule; end
4
-
5
- class TestMagicMultiConnection < Test::Unit::TestCase
6
-
7
- def setup
8
- create_fixtures :people
9
- end
10
-
11
- def test_classes
12
- assert_nothing_raised(Exception) { Person }
13
- assert_equal('ActiveRecord::Base', Person.active_connection_name)
14
- assert(normal_person = Person.find(1), "Cannot get Person instances")
15
- assert_nothing_raised(Exception) { ContactRepository::Person }
16
- assert_equal(Person, ContactRepository::Person.superclass)
17
- assert_equal('ContactRepository::Person', ContactRepository::Person.name)
18
- assert_equal('ContactRepository::Person', ContactRepository::Person.active_connection_name)
19
- assert_equal(0, ContactRepository::Person.count)
20
- end
21
-
22
- def test_normal_modules_shouldnt_do_anything
23
- assert_raise(NameError) { NormalModule::Person }
24
-
25
- end
26
- end
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ module NormalModule; end
4
+
5
+ class TestMagicMultiConnection < Test::Unit::TestCase
6
+
7
+ def setup
8
+ create_fixtures :people, :addresses
9
+ end
10
+
11
+ def test_classes
12
+ assert_nothing_raised(Exception) { Person }
13
+ assert_equal('ActiveRecord::Base', Person.active_connection_name)
14
+ assert(normal_person = Person.find(1), "Cannot get Person instances")
15
+ assert_nothing_raised(Exception) { ContactRepository::Person }
16
+ assert_equal(Person, ContactRepository::Person.superclass)
17
+ assert_equal('ContactRepository::Person', ContactRepository::Person.name)
18
+ assert_equal('ContactRepository::Person', ContactRepository::Person.active_connection_name)
19
+ assert_equal(0, ContactRepository::Person.count)
20
+ end
21
+
22
+ def test_normal_modules_shouldnt_do_anything
23
+ assert_raise(NameError) { NormalModule::Person }
24
+
25
+ end
26
+
27
+ end
@@ -0,0 +1,46 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestMmcAssociations < Test::Unit::TestCase
4
+
5
+ def setup
6
+
7
+ end
8
+
9
+ def test_namespace_associations
10
+ assert_nothing_raised(Exception) do
11
+ Army::Soldier
12
+ Army::Assignment
13
+ Paycheck
14
+ Justice::Citation
15
+ end
16
+
17
+ assert_equal Army::Assignment, Army::Soldier.reflections[:assignments].klass
18
+ assert_equal Paycheck, Army::Soldier.reflections[:paychecks].klass
19
+
20
+ assert_equal true, Army::Classified.namespace_reflections_mirror_db
21
+
22
+ assert_nothing_raised(Exception) { Army::Classified::Soldier }
23
+ assert_equal Army::Classified::Assignment, Army::Classified::Soldier.reflections[:assignments].klass
24
+ assert_equal Paycheck, Army::Classified::Soldier.reflections[:paychecks].klass
25
+ assert_equal Justice::Citation, Army::Classified::Soldier.reflections[:citations].klass
26
+ end
27
+
28
+ def test_explicit_associations
29
+ assert_nothing_raised(Exception) do
30
+ Person
31
+ Habit
32
+ Address
33
+ end
34
+
35
+ assert_equal Address, Person.reflections[:addresses].klass
36
+ assert_equal :default, Person.reflections[:addresses].mirror_db_connection
37
+ assert_equal Habit, Person.reflections[:habits].klass
38
+ assert_equal true, Person.reflections[:habits].mirror_db_connection
39
+
40
+ assert_equal false, ContactRepository.namespace_reflections_mirror_db
41
+
42
+ assert_nothing_raised(Exception) { ContactRepository::Person }
43
+ assert_equal Address, ContactRepository::Person.reflections[:addresses].klass
44
+ assert_equal ContactRepository::Habit, ContactRepository::Person.reflections[:habits].klass
45
+ end
46
+ end
File without changes
File without changes
@@ -1,340 +1,354 @@
1
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
- <head>
5
- <link rel="stylesheet" href="stylesheets/screen.css" type="text/css" media="screen" />
6
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
7
- <title>
8
- Magic Multi-Connections
9
- </title>
10
- <script src="javascripts/rounded_corners_lite.inc.js" type="text/javascript"></script>
11
- <style>
12
-
13
- </style>
14
- <script type="text/javascript">
15
- window.onload = function() {
16
- settings = {
17
- tl: { radius: 10 },
18
- tr: { radius: 10 },
19
- bl: { radius: 10 },
20
- br: { radius: 10 },
21
- antiAlias: true,
22
- autoPad: true,
23
- validTags: ["div"]
24
- }
25
- var versionBox = new curvyCorners(settings, document.getElementById("version"));
26
- versionBox.applyCornersToAll();
27
- }
28
- </script>
29
- </head>
30
- <body>
31
- <div id="main">
32
- <p><a href="/">&#x21A9; More Magic</a></p>
33
- <h1 class=primary>Magic Multi-Connections</h1>
34
- <div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/magicmodels"; return false'>
35
- Get Version
36
- <a href="http://rubyforge.org/projects/magicmodels" class="numbers">1.0.0</a>
37
- </div>
38
- <h1>&#x2192; Ruby on Rails</h1>
39
-
40
-
41
- <h1>&#x2192; ActiveRecords</h1>
42
-
43
-
44
- <h2>What</h2>
45
-
46
-
47
- <p>ActiveRecord models are allowed one connection to a database at a time, per class. Ruby on Rails sets up the default connection based on your database.yml configuration to automatically select <strong>development</strong>, <strong>test</strong> or <strong>production</strong>.</p>
48
-
49
-
50
- <p>But, what if you want to access two or more databases &#8211; have 2+ connections open &#8211; at the same time. ActiveRecord requires that you subclass <code>ActiveRecord::Base</code>.</p>
51
-
52
-
53
- <p>That prevents you doing migrations from one database to another. It prevents you using one set of model classes on two or more databases with the same schema.</p>
54
-
55
-
56
- <p>Magic Multi-Connections allows you to write your models once, and use them for multiple database Rails databases at the same time. How? Using magical namespacing.</p>
57
-
58
-
59
- <p><pre class="syntax"><span class="keyword">class </span><span class="class">Person</span> <span class="punct">&lt;</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span><span class="punct">;</span> <span class="keyword">end</span>
60
- <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span><span class="punct">.</span><span class="ident">establish_connection</span> <span class="symbol">:production</span>
61
- <span class="constant">Person</span><span class="punct">.</span><span class="ident">connection</span> <span class="comment"># =&gt; production</span>
62
-
63
- <span class="keyword">module </span><span class="module">ContactRepository</span>
64
- <span class="ident">establish_connection</span> <span class="symbol">:contact_repo</span>
65
- <span class="keyword">end</span>
66
- <span class="constant">ContactRepository</span><span class="punct">::</span><span class="constant">Person</span><span class="punct">.</span><span class="ident">connection</span> <span class="comment"># =&gt; contact_repo</span>
67
-
68
- <span class="ident">old_person</span> <span class="punct">=</span> <span class="constant">ContactRepository</span><span class="punct">::</span><span class="constant">Person</span><span class="punct">.</span><span class="ident">find_by_email</span><span class="punct">(</span><span class="ident">email</span><span class="punct">)</span>
69
- <span class="ident">person</span> <span class="punct">=</span> <span class="ident">old_person</span><span class="punct">.</span><span class="ident">create_as</span><span class="punct">(</span><span class="constant">Person</span><span class="punct">)</span>
70
- </pre></p>
71
-
72
-
73
- <p>You do not have to redefine your models for the multi-connection module <code>ContactRepository</code>, they are automatically picked up for you. Magically.</p>
74
-
75
-
76
- <h2>Installing</h2>
77
-
78
-
79
- <p><pre class="syntax"><span class="ident">sudo</span> <span class="ident">gem</span> <span class="ident">install</span> <span class="ident">magic_multi_connections</span></pre></p>
80
-
81
-
82
- <p>Rails: Add the following to the bottom of your <code>environment.rb</code> file</p>
83
-
84
-
85
- <p><pre class="syntax"><span class="ident">require</span> <span class="punct">'</span><span class="string">magic_multi_connections</span><span class="punct">'</span></pre></p>
86
-
87
-
88
- <p>Ruby scripts: Add the following to the top of your script</p>
89
-
90
-
91
- <p><pre class="syntax"><span class="ident">require</span> <span class="punct">'</span><span class="string">rubygems</span><span class="punct">'</span>
92
- <span class="ident">require</span> <span class="punct">'</span><span class="string">magic_multi_connections</span><span class="punct">'</span></pre></p>
93
-
94
-
95
- <h2>Demonstration with Rails</h2>
96
-
97
-
98
- <p>A quick demonstration within Rails to provide a parallel &#8220;private&#8221; database for an application.</p>
99
-
100
-
101
- <h3>1. Create rails app</h3>
102
-
103
-
104
- <p>Using sqlite3 here, but use your preferred db:</p>
105
-
106
-
107
- <pre>&gt; rails privacy -d sqlite3
108
- &gt; cd privacy
109
- &gt; ruby script/generate model Person
110
- &gt; cp config/environments/development.rb config/environments/private.rb
111
- </pre>
112
-
113
- <p>The last line allows us to play with our <strong>private</strong> database within the console and rake tasks.</p>
114
-
115
-
116
- <h3>2. Edit <strong>config/database.yml</strong> and add our private database:</h3>
117
-
118
-
119
- <p>Add the following to the bottom of <strong>config/database.yml</strong></p>
120
-
121
-
122
- <p><pre class="syntax">
123
- <span class="key">private</span><span class="punct">:</span>
124
- <span class="key">adapter</span><span class="punct">:</span> sqlite3
125
- <span class="key">database</span><span class="punct">:</span> db/private.sqlite3
126
- </pre></p>
127
-
128
-
129
- <h3>3. Create a database schema</h3>
130
-
131
-
132
- <p>Edit <strong>db/migrate/001_create_people.rb</strong></p>
133
-
134
-
135
- <p><pre class="syntax"><span class="keyword">class </span><span class="class">CreatePeople</span> <span class="punct">&lt;</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Migration</span>
136
- <span class="keyword">def </span><span class="method">self.up</span>
137
- <span class="ident">create_table</span> <span class="symbol">:people</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">t</span><span class="punct">|</span>
138
- <span class="ident">t</span><span class="punct">.</span><span class="ident">column</span> <span class="symbol">:name</span><span class="punct">,</span> <span class="symbol">:string</span>
139
- <span class="keyword">end</span>
140
- <span class="keyword">end</span>
141
-
142
- <span class="keyword">def </span><span class="method">self.down</span>
143
- <span class="ident">drop_table</span> <span class="symbol">:people</span>
144
- <span class="keyword">end</span>
145
- <span class="keyword">end</span>
146
- </pre></p>
147
-
148
-
149
- <p>From the command line, migrate this to our <strong>development</strong> and <strong>private</strong> databases:</p>
150
-
151
-
152
- <pre>&gt; rake db:migrate
153
- &gt; rake db:migrate RAILS_ENV=private</pre>
154
-
155
- <h3>4. Add some data to databases</h3>
156
-
157
-
158
- <p><pre class="syntax"><span class="punct">&gt;</span> <span class="ident">ruby</span> <span class="ident">script</span><span class="punct">/</span><span class="ident">console</span> <span class="ident">development</span>
159
- <span class="punct">&gt;&gt;</span> <span class="constant">Person</span><span class="punct">.</span><span class="ident">create</span><span class="punct">(</span><span class="symbol">:name</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">Nic</span><span class="punct">')</span>
160
- <span class="punct">&gt;&gt;</span> <span class="constant">Person</span><span class="punct">.</span><span class="ident">create</span><span class="punct">(</span><span class="symbol">:name</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">Banjo</span><span class="punct">')</span>
161
- <span class="punct">&gt;&gt;</span> <span class="ident">exit</span>
162
- <span class="punct">&gt;</span> <span class="ident">ruby</span> <span class="ident">script</span><span class="punct">/</span><span class="ident">console</span> <span class="ident">private</span>
163
- <span class="punct">&gt;&gt;</span> <span class="constant">Person</span><span class="punct">.</span><span class="ident">create</span><span class="punct">(</span><span class="symbol">:name</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">Super Magical Nic</span><span class="punct">')</span>
164
- <span class="punct">&gt;&gt;</span> <span class="ident">exit</span></pre></p>
165
-
166
-
167
- <p>Now it should be obvious which database our app is accessing.</p>
168
-
169
-
170
- <h3>5. Update environment.rb</h3>
171
-
172
-
173
- <p>Edit <strong>config/environment.rb</strong> to include the library and create the <strong>Private</strong> module.</p>
174
-
175
-
176
- <p>Add the following to the end of the file.</p>
177
-
178
-
179
- <p><pre class="syntax">
180
- <span class="ident">require</span> <span class="punct">&quot;</span><span class="string">magic_multi_connections</span><span class="punct">&quot;</span>
181
-
182
- <span class="keyword">module </span><span class="module">Private</span>
183
- <span class="ident">establish_connection</span> <span class="symbol">:private</span>
184
- <span class="keyword">end</span>
185
- </pre></p>
186
-
187
-
188
- <p>This tells the <strong>Private</strong> module that any model class that is requested will be assigned a connection to the <strong>private</strong> database, as defined in the <strong>config/database.yml</strong> specification.</p>
189
-
190
-
191
- <h3>6. Setup a controller</h3>
192
-
193
-
194
- <p>Create a <strong>people</strong> controller with a <strong>index</strong> action</p>
195
-
196
-
197
- <pre>&gt; ruby script/generate controller people index</pre>
198
-
199
- <p>Edit your controller <strong>app/controllers/people_controller.rb</strong></p>
200
-
201
-
202
- <p><pre class="syntax"><span class="keyword">class </span><span class="class">PeopleController</span> <span class="punct">&lt;</span> <span class="constant">ApplicationController</span>
203
-
204
- <span class="ident">before_filter</span> <span class="symbol">:check_private</span>
205
-
206
- <span class="keyword">def </span><span class="method">index</span>
207
- <span class="attribute">@people</span> <span class="punct">=</span> <span class="attribute">@mod</span><span class="punct">::</span><span class="constant">Person</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="symbol">:all</span><span class="punct">)</span>
208
- <span class="keyword">end</span>
209
-
210
- <span class="ident">private</span>
211
- <span class="keyword">def </span><span class="method">check_private</span>
212
- <span class="attribute">@mod</span> <span class="punct">=</span> <span class="ident">params</span><span class="punct">[</span><span class="symbol">:private</span><span class="punct">]</span> <span class="punct">?</span> <span class="constant">Private</span> <span class="punct">:</span> <span class="constant">Object</span>
213
- <span class="keyword">end</span>
214
- <span class="keyword">end</span>
215
- </pre></p>
216
-
217
-
218
- <p>The <strong>check_private</strong> action is a hack to demonstrate one method for selecting the database. In reality, a stupid one for hiding a &#8220;private&#8221; database, but you get the point.</p>
219
-
220
-
221
- <p>After <strong>check_private</strong> is called, <strong>@mod</strong> is either the <strong>Object</strong> (default) module or the <strong>Private</strong> module. The <strong>Person</strong> class is accessible through either of them.</p>
222
-
223
-
224
- <p>Yes, <code>@mod::Person</code> is uglier than just <code>Person</code>. Sorry.</p>
225
-
226
-
227
- <h3>7. Setup the index.rhtml view</h3>
228
-
229
-
230
- <p>Edit <strong>app/views/people/index.rhtml</strong></p>
231
-
232
-
233
- <p><pre class="syntax">&lt;h1&gt;&lt;%= @mod::Person %&gt;&lt;/h1&gt;
234
- &lt;h2&gt;&lt;%= @mod::Person.active_connection_name %&gt;&lt;/h2&gt;
235
-
236
- &lt;ol&gt;
237
- &lt;% @people.each do |person| -%&gt;
238
- &lt;li&gt;&lt;%= &quot;#{person.name} - #{person.class}&quot; %&gt;&lt;/li&gt;
239
- &lt;% end -%&gt;
240
- &lt;/ol&gt;
241
- </pre></p>
242
-
243
-
244
- <h3>8. Test our multi-connection Rails app</h3>
245
-
246
-
247
- <p>Launch the app</p>
248
-
249
-
250
- <pre>&gt; mongrel_rails start</pre>
251
-
252
- <p>In your browser, go to <a href="http://localhost:3000/people">http://localhost:3000/people</a> and see the list of people: Nic and Banjo.</p>
253
-
254
-
255
- <p>Now, to see the private database, go to <a href="http://localhost:3000/people?private=1">http://localhost:3000/people?private=1</a> and see the private list. Its so private, I won&#8217;t show it here.</p>
256
-
257
-
258
- <p>Note: you may need to refresh the private url to see the results. Perhaps Rails is caching the <span class="caps">SQL</span> even though its a different connection to a different database. If you know what&#8217;s happening here, please <a href="mailto:drnicwilliams@gmail.com?subject=MMC+caching+problem">email me</a> or the <a href="mailto:magicmodels@googlegroups.com?subject=MMC+caching+problem">forum</a>. Thanks.</p>
259
-
260
-
261
- <h3>9. End</h3>
262
-
263
-
264
- <p>There ends our example of a Rails application using one model class to access multiple databases cleanly.</p>
265
-
266
-
267
- <h2>Pre-existing modules</h2>
268
-
269
-
270
- <p>In Rails, model files are placed in the <strong>app/models</strong> folder. If you place them in a subfolder, say <strong>app/models/admin</strong>, then those model classes are access via module namespaces.</p>
271
-
272
-
273
- <p>So, <strong>app/models/admin/page.rb</strong> represents the <code>Admin::Page</code> class.</p>
274
-
275
-
276
- <p>Magic Multi-Connections works for these model classes as well.</p>
277
-
278
-
279
- <p><pre class="syntax"><span class="constant">Admin</span><span class="punct">.</span><span class="ident">establish_connection</span> <span class="symbol">:admin_dev</span>
280
- <span class="constant">Admin</span><span class="punct">::</span><span class="constant">Page</span><span class="punct">.</span><span class="ident">active_connection_name</span> <span class="comment"># =&gt; &quot;Admin::Page&quot;</span>
281
- </pre></p>
282
-
283
-
284
- <h2>Other tricks</h2>
285
-
286
-
287
- <p>The Magic Multi-Connections includes <code>diff</code> and <code>diff?</code> methods extracted from the <a href="http://tfletcher.com/svn/rails-plugins/riff/README">Riff plugin</a> by <a href="http://tfletcher.com/">Tim Fletcher</a>, so that <code>id</code> values are ignored when comparing objects from different connections/namespaces.</p>
288
-
289
-
290
- <p><pre class="syntax"><span class="comment"># Detect differences between two activerecords, e.g.</span>
291
- <span class="ident">new_person</span> <span class="punct">=</span> <span class="constant">Person</span><span class="punct">.</span><span class="ident">find_by_username</span><span class="punct">('</span><span class="string">drnic</span><span class="punct">')</span>
292
- <span class="ident">old_person</span> <span class="punct">=</span> <span class="constant">ContactRepository</span><span class="punct">::</span><span class="constant">Person</span><span class="punct">.</span><span class="ident">find_by_username</span><span class="punct">('</span><span class="string">drnic</span><span class="punct">')</span>
293
-
294
- <span class="ident">new_person</span><span class="punct">.</span><span class="ident">diff?</span><span class="punct">(</span><span class="ident">old_person</span><span class="punct">)</span> <span class="comment"># =&gt; true</span>
295
-
296
- <span class="ident">new_person</span><span class="punct">.</span><span class="ident">diff</span><span class="punct">(</span><span class="ident">old_person</span><span class="punct">)</span> <span class="comment"># =&gt; { :name =&gt; ['Dr Nic', 'Nic'], :age =&gt; [32, 20] }</span>
297
- </pre></p>
298
-
299
-
300
- <h2>Dr Nic&#8217;s Blog</h2>
301
-
302
-
303
- <p><a href="http://www.drnicwilliams.com">http://www.drnicwilliams.com</a> &#8211; for future announcements and
304
- other stories and things.</p>
305
-
306
-
307
- <h2>Forum</h2>
308
-
309
-
310
- <p>Discussion about the Magic Multi-Connections is on the Magic Models forum:</p>
311
-
312
-
313
- <p><a href="http://groups.google.com/group/magicmodels">http://groups.google.com/group/magicmodels</a></p>
314
-
315
-
316
- <h2>Licence</h2>
317
-
318
-
319
- <p>This code is free to use under the terms of the <span class="caps">MIT</span> licence.</p>
320
-
321
-
322
- <h2>Contact</h2>
323
-
324
-
325
- <p>Comments are welcome. Send an email to <a href="mailto:drnicwilliams@gmail.com">Dr Nic Williams</a>.</p>
326
- <p class="coda">
327
- <a href="mailto:drnicwilliams@gmail.com">Dr Nic</a>, 9th April 2007<br>
328
- Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
329
- </p>
330
- </div>
331
-
332
- <script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
333
- </script>
334
- <script type="text/javascript">
335
- _uacct = "UA-567811-2";
336
- urchinTracker();
337
- </script>
338
-
339
- </body>
340
- </html>
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <link rel="stylesheet" href="stylesheets/screen.css" type="text/css" media="screen" />
6
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
7
+ <title>
8
+ Magic Multi-Connections
9
+ </title>
10
+ <script src="javascripts/rounded_corners_lite.inc.js" type="text/javascript"></script>
11
+ <style>
12
+
13
+ </style>
14
+ <script type="text/javascript">
15
+ window.onload = function() {
16
+ settings = {
17
+ tl: { radius: 10 },
18
+ tr: { radius: 10 },
19
+ bl: { radius: 10 },
20
+ br: { radius: 10 },
21
+ antiAlias: true,
22
+ autoPad: true,
23
+ validTags: ["div"]
24
+ }
25
+ var versionBox = new curvyCorners(settings, document.getElementById("version"));
26
+ versionBox.applyCornersToAll();
27
+ }
28
+ </script>
29
+ </head>
30
+ <body>
31
+ <div id="main">
32
+ <p><a href="/">&#x21A9; More Magic</a></p>
33
+ <h1 class=primary>Magic Multi-Connections</h1>
34
+ <div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/magicmodels"; return false'>
35
+ Get Version
36
+ <a href="http://rubyforge.org/projects/magicmodels" class="numbers">1.2.0</a>
37
+ </div>
38
+ <h1>&#x2192; Ruby on Rails</h1>
39
+
40
+
41
+ <h1>&#x2192; ActiveRecords</h1>
42
+
43
+
44
+ <h2><span class="caps">WARNING</span></h2>
45
+
46
+
47
+ <p>Despite the 1.1.0 version number, this gem is not quite production ready. Various people have <a href="http://joshknowles.com/2007/6/17/migrations-pains">experienced problems</a> using the 1.0.0 version. A solution was found to deal with this issue but it has not been fully tested, so please subscribe to the <a href="http://groups.google.com/group/magicmodels">forum</a> or <a href="http://rubyforge.org/export/rss_sfnewreleases.php">RubyForge news</a> for any updates.</p>
48
+
49
+
50
+ <h2>What</h2>
51
+
52
+
53
+ <p>ActiveRecord models are allowed one connection to a database at a time, per class. Ruby on Rails sets up the default connection based on your database.yml configuration to automatically select <strong>development</strong>, <strong>test</strong> or <strong>production</strong>.</p>
54
+
55
+
56
+ <p>But, what if you want to access two or more databases &#8211; have 2+ connections open &#8211; at the same time. ActiveRecord requires that you subclass <code>ActiveRecord::Base</code>.</p>
57
+
58
+
59
+ <p>That prevents you doing migrations from one database to another. It prevents you using one set of model classes on two or more databases with the same schema.</p>
60
+
61
+
62
+ <p>Magic Multi-Connections allows you to write your models once, and use them for multiple database Rails databases at the same time. How? Using magical namespacing.</p>
63
+
64
+
65
+ <p><pre class="syntax"><span class="keyword">class </span><span class="class">Person</span> <span class="punct">&lt;</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span><span class="punct">;</span> <span class="keyword">end</span>
66
+ <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Base</span><span class="punct">.</span><span class="ident">establish_connection</span> <span class="symbol">:production</span>
67
+ <span class="constant">Person</span><span class="punct">.</span><span class="ident">connection</span> <span class="comment"># =&gt; production</span>
68
+
69
+ <span class="keyword">module </span><span class="module">ContactRepository</span>
70
+ <span class="ident">establish_connection</span> <span class="symbol">:contact_repo</span>
71
+ <span class="keyword">end</span>
72
+ <span class="constant">ContactRepository</span><span class="punct">::</span><span class="constant">Person</span><span class="punct">.</span><span class="ident">connection</span> <span class="comment"># =&gt; contact_repo</span>
73
+
74
+ <span class="ident">old_person</span> <span class="punct">=</span> <span class="constant">ContactRepository</span><span class="punct">::</span><span class="constant">Person</span><span class="punct">.</span><span class="ident">find_by_email</span><span class="punct">(</span><span class="ident">email</span><span class="punct">)</span>
75
+ <span class="ident">person</span> <span class="punct">=</span> <span class="ident">old_person</span><span class="punct">.</span><span class="ident">create_as</span><span class="punct">(</span><span class="constant">Person</span><span class="punct">)</span>
76
+ </pre></p>
77
+
78
+
79
+ <p>You do not have to redefine your models for the multi-connection module <code>ContactRepository</code>, they are automatically picked up for you. Magically.</p>
80
+
81
+
82
+ <p><span class="caps">TODO</span>: Example about Associations</p>
83
+
84
+
85
+ <h2>Issues</h2>
86
+
87
+
88
+ Despite the 1.1.0 version of this gem there are still a number of issues with this gem:
89
+ <ul>
90
+ <li>Single Table Inheritance is not currently supported</li>
91
+ <li>No connection pooling for alternate databases</li>
92
+ </ul>
93
+
94
+ <p>Any help would be greatly appreciated</p>
95
+
96
+
97
+ <h2>Installing</h2>
98
+
99
+
100
+ <p><pre class="syntax"><span class="ident">sudo</span> <span class="ident">gem</span> <span class="ident">install</span> <span class="ident">magic_multi_connections</span></pre></p>
101
+
102
+
103
+ <p>Rails: Add the following to the bottom of your <code>environment.rb</code> file</p>
104
+
105
+
106
+ <p><pre class="syntax"><span class="ident">require</span> <span class="punct">'</span><span class="string">magic_multi_connections</span><span class="punct">'</span></pre></p>
107
+
108
+
109
+ <p>Ruby scripts: Add the following to the top of your script</p>
110
+
111
+
112
+ <p><pre class="syntax"><span class="ident">require</span> <span class="punct">'</span><span class="string">rubygems</span><span class="punct">'</span>
113
+ <span class="ident">require</span> <span class="punct">'</span><span class="string">magic_multi_connections</span><span class="punct">'</span></pre></p>
114
+
115
+
116
+ <h2>Demonstration with Rails</h2>
117
+
118
+
119
+ <p>A quick demonstration within Rails to provide a parallel &#8220;private&#8221; database for an application.</p>
120
+
121
+
122
+ <h3>1. Create rails app</h3>
123
+
124
+
125
+ <p>Using sqlite3 here, but use your preferred db:</p>
126
+
127
+
128
+ <pre>&gt; rails privacy -d sqlite3
129
+ &gt; cd privacy
130
+ &gt; ruby script/generate model Person
131
+ &gt; cp config/environments/development.rb config/environments/private.rb
132
+ </pre>
133
+
134
+ <p>The last line allows us to play with our <strong>private</strong> database within the console and rake tasks.</p>
135
+
136
+
137
+ <h3>2. Edit <strong>config/database.yml</strong> and add our private database:</h3>
138
+
139
+
140
+ <p>Add the following to the bottom of <strong>config/database.yml</strong></p>
141
+
142
+
143
+ <p><pre class="syntax">
144
+ <span class="key">private</span><span class="punct">:</span>
145
+ <span class="key">adapter</span><span class="punct">:</span> sqlite3
146
+ <span class="key">database</span><span class="punct">:</span> db/private.sqlite3
147
+ </pre></p>
148
+
149
+
150
+ <h3>3. Create a database schema</h3>
151
+
152
+
153
+ <p>Edit <strong>db/migrate/001_create_people.rb</strong></p>
154
+
155
+
156
+ <p><pre class="syntax"><span class="keyword">class </span><span class="class">CreatePeople</span> <span class="punct">&lt;</span> <span class="constant">ActiveRecord</span><span class="punct">::</span><span class="constant">Migration</span>
157
+ <span class="keyword">def </span><span class="method">self.up</span>
158
+ <span class="ident">create_table</span> <span class="symbol">:people</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">t</span><span class="punct">|</span>
159
+ <span class="ident">t</span><span class="punct">.</span><span class="ident">column</span> <span class="symbol">:name</span><span class="punct">,</span> <span class="symbol">:string</span>
160
+ <span class="keyword">end</span>
161
+ <span class="keyword">end</span>
162
+
163
+ <span class="keyword">def </span><span class="method">self.down</span>
164
+ <span class="ident">drop_table</span> <span class="symbol">:people</span>
165
+ <span class="keyword">end</span>
166
+ <span class="keyword">end</span>
167
+ </pre></p>
168
+
169
+
170
+ <p>From the command line, migrate this to our <strong>development</strong> and <strong>private</strong> databases:</p>
171
+
172
+
173
+ <pre>&gt; rake db:migrate
174
+ &gt; rake db:migrate RAILS_ENV=private</pre>
175
+
176
+ <h3>4. Add some data to databases</h3>
177
+
178
+
179
+ <p><pre class="syntax"><span class="punct">&gt;</span> <span class="ident">ruby</span> <span class="ident">script</span><span class="punct">/</span><span class="ident">console</span> <span class="ident">development</span>
180
+ <span class="punct">&gt;&gt;</span> <span class="constant">Person</span><span class="punct">.</span><span class="ident">create</span><span class="punct">(</span><span class="symbol">:name</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">Nic</span><span class="punct">')</span>
181
+ <span class="punct">&gt;&gt;</span> <span class="constant">Person</span><span class="punct">.</span><span class="ident">create</span><span class="punct">(</span><span class="symbol">:name</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">Banjo</span><span class="punct">')</span>
182
+ <span class="punct">&gt;&gt;</span> <span class="ident">exit</span>
183
+ <span class="punct">&gt;</span> <span class="ident">ruby</span> <span class="ident">script</span><span class="punct">/</span><span class="ident">console</span> <span class="ident">private</span>
184
+ <span class="punct">&gt;&gt;</span> <span class="constant">Person</span><span class="punct">.</span><span class="ident">create</span><span class="punct">(</span><span class="symbol">:name</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">Super Magical Nic</span><span class="punct">')</span>
185
+ <span class="punct">&gt;&gt;</span> <span class="ident">exit</span></pre></p>
186
+
187
+
188
+ <p>Now it should be obvious which database our app is accessing.</p>
189
+
190
+
191
+ <h3>5. Update environment.rb</h3>
192
+
193
+
194
+ <p>Edit <strong>config/environment.rb</strong> to include the library and create the <strong>Private</strong> module.</p>
195
+
196
+
197
+ <p>Add the following to the end of the file.</p>
198
+
199
+
200
+ <p><pre class="syntax">
201
+ <span class="ident">require</span> <span class="punct">&quot;</span><span class="string">magic_multi_connections</span><span class="punct">&quot;</span>
202
+
203
+ <span class="keyword">module </span><span class="module">Private</span>
204
+ <span class="ident">establish_connection</span> <span class="symbol">:private</span>
205
+ <span class="keyword">end</span>
206
+ </pre></p>
207
+
208
+
209
+ <p>This tells the <strong>Private</strong> module that any model class that is requested will be assigned a connection to the <strong>private</strong> database, as defined in the <strong>config/database.yml</strong> specification.</p>
210
+
211
+
212
+ <h3>6. Setup a controller</h3>
213
+
214
+
215
+ <p>Create a <strong>people</strong> controller with a <strong>index</strong> action</p>
216
+
217
+
218
+ <pre>&gt; ruby script/generate controller people index</pre>
219
+
220
+ <p>Edit your controller <strong>app/controllers/people_controller.rb</strong></p>
221
+
222
+
223
+ <p><pre class="syntax"><span class="keyword">class </span><span class="class">PeopleController</span> <span class="punct">&lt;</span> <span class="constant">ApplicationController</span>
224
+
225
+ <span class="ident">before_filter</span> <span class="symbol">:check_private</span>
226
+
227
+ <span class="keyword">def </span><span class="method">index</span>
228
+ <span class="attribute">@people</span> <span class="punct">=</span> <span class="attribute">@mod</span><span class="punct">::</span><span class="constant">Person</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="symbol">:all</span><span class="punct">)</span>
229
+ <span class="keyword">end</span>
230
+
231
+ <span class="ident">private</span>
232
+ <span class="keyword">def </span><span class="method">check_private</span>
233
+ <span class="attribute">@mod</span> <span class="punct">=</span> <span class="ident">params</span><span class="punct">[</span><span class="symbol">:private</span><span class="punct">]</span> <span class="punct">?</span> <span class="constant">Private</span> <span class="punct">:</span> <span class="constant">Object</span>
234
+ <span class="keyword">end</span>
235
+ <span class="keyword">end</span>
236
+ </pre></p>
237
+
238
+
239
+ <p>The <strong>check_private</strong> action is a hack to demonstrate one method for selecting the database. In reality, a stupid one for hiding a &#8220;private&#8221; database, but you get the point.</p>
240
+
241
+
242
+ <p>After <strong>check_private</strong> is called, <strong>@mod</strong> is either the <strong>Object</strong> (default) module or the <strong>Private</strong> module. The <strong>Person</strong> class is accessible through either of them.</p>
243
+
244
+
245
+ <p>Yes, <code>@mod::Person</code> is uglier than just <code>Person</code>. Sorry.</p>
246
+
247
+
248
+ <h3>7. Setup the index.rhtml view</h3>
249
+
250
+
251
+ <p>Edit <strong>app/views/people/index.rhtml</strong></p>
252
+
253
+
254
+ <p><pre class="syntax">&lt;h1&gt;&lt;%= @mod::Person %&gt;&lt;/h1&gt;
255
+ &lt;h2&gt;&lt;%= @mod::Person.active_connection_name %&gt;&lt;/h2&gt;
256
+
257
+ &lt;ol&gt;
258
+ &lt;% @people.each do |person| -%&gt;
259
+ &lt;li&gt;&lt;%= &quot;#{person.name} - #{person.class}&quot; %&gt;&lt;/li&gt;
260
+ &lt;% end -%&gt;
261
+ &lt;/ol&gt;
262
+ </pre></p>
263
+
264
+
265
+ <h3>8. Test our multi-connection Rails app</h3>
266
+
267
+
268
+ <p>Launch the app</p>
269
+
270
+
271
+ <pre>&gt; mongrel_rails start</pre>
272
+
273
+ <p>In your browser, go to <a href="http://localhost:3000/people">http://localhost:3000/people</a> and see the list of people: Nic and Banjo.</p>
274
+
275
+
276
+ <p>Now, to see the private database, go to <a href="http://localhost:3000/people?private=1">http://localhost:3000/people?private=1</a> and see the private list. Its so private, I won&#8217;t show it here.</p>
277
+
278
+
279
+ <p>Note: you may need to refresh the private url to see the results. Perhaps Rails is caching the <span class="caps">SQL</span> even though its a different connection to a different database. If you know what&#8217;s happening here, please <a href="mailto:drnicwilliams@gmail.com?subject=MMC+caching+problem">email me</a> or the <a href="mailto:magicmodels@googlegroups.com?subject=MMC+caching+problem">forum</a>. Thanks.</p>
280
+
281
+
282
+ <h3>9. End</h3>
283
+
284
+
285
+ <p>There ends our example of a Rails application using one model class to access multiple databases cleanly.</p>
286
+
287
+
288
+ <h2>Pre-existing modules</h2>
289
+
290
+
291
+ <p>In Rails, model files are placed in the <strong>app/models</strong> folder. If you place them in a subfolder, say <strong>app/models/admin</strong>, then those model classes are access via module namespaces.</p>
292
+
293
+
294
+ <p>So, <strong>app/models/admin/page.rb</strong> represents the <code>Admin::Page</code> class.</p>
295
+
296
+
297
+ <p>Magic Multi-Connections works for these model classes as well.</p>
298
+
299
+
300
+ <p><pre class="syntax"><span class="constant">Admin</span><span class="punct">.</span><span class="ident">establish_connection</span> <span class="symbol">:admin_dev</span>
301
+ <span class="constant">Admin</span><span class="punct">::</span><span class="constant">Page</span><span class="punct">.</span><span class="ident">active_connection_name</span> <span class="comment"># =&gt; &quot;Admin::Page&quot;</span>
302
+ </pre></p>
303
+
304
+
305
+ <h2>Related articles</h2>
306
+
307
+
308
+ <ul>
309
+ <li>Original blog article &#8211; <a href="http://drnicwilliams.com/2007/04/12/magic-multi-connections-a-facility-in-rails-to-talk-to-more-than-one-database-at-a-time/">Magic Multi-Connections: A “facility in Rails to talk to more than one database at a time</a></li>
310
+ <li><a href="http://www.loudthinking.com/arc/000610.html">Discussed by <span class="caps">DHH</span></a></li>
311
+ </ul>
312
+
313
+
314
+ <h2>Dr Nic&#8217;s Blog</h2>
315
+
316
+
317
+ <p><a href="http://www.drnicwilliams.com">http://www.drnicwilliams.com</a> &#8211; for future announcements and
318
+ other stories and things.</p>
319
+
320
+
321
+ <h2>Forum</h2>
322
+
323
+
324
+ <p>Discussion about the Magic Multi-Connections is on the Magic Models forum:</p>
325
+
326
+
327
+ <p><a href="http://groups.google.com/group/magicmodels">http://groups.google.com/group/magicmodels</a></p>
328
+
329
+
330
+ <h2>Licence</h2>
331
+
332
+
333
+ <p>This code is free to use under the terms of the <span class="caps">MIT</span> licence.</p>
334
+
335
+
336
+ <h2>Contact</h2>
337
+
338
+
339
+ <p>Comments are welcome. Send an email to <a href="mailto:drnicwilliams@gmail.com">Dr Nic Williams</a>.</p>
340
+ <p class="coda">
341
+ <a href="mailto:drnicwilliams@gmail.com">Dr Nic</a>, 2nd January 2008<br>
342
+ Theme extended from <a href="http://rb2js.rubyforge.org/">Paul Battley</a>
343
+ </p>
344
+ </div>
345
+
346
+ <script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
347
+ </script>
348
+ <script type="text/javascript">
349
+ _uacct = "UA-567811-2";
350
+ urchinTracker();
351
+ </script>
352
+
353
+ </body>
354
+ </html>