magic_multi_connections 1.0.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
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>