magic_multi_connections 1.0.0
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.
- data/CHANGELOG.txt +0 -0
- data/History.txt +3 -0
- data/Manifest.txt +32 -0
- data/README.txt +3 -0
- data/Rakefile +103 -0
- data/lib/ext_active_record/connection_specification.rb +24 -0
- data/lib/magic_multi_connections/connected.rb +29 -0
- data/lib/magic_multi_connections/module.rb +26 -0
- data/lib/magic_multi_connections/version.rb +9 -0
- data/lib/magic_multi_connections.rb +21 -0
- data/scripts/txt2html +67 -0
- data/scripts/txt2js +59 -0
- data/setup.rb +1585 -0
- data/test/connections/native_postgresql/connection.rb +20 -0
- data/test/fixtures/contact_repository.rb +3 -0
- data/test/fixtures/db_definitions/postgresql.sql +7 -0
- data/test/fixtures/people.yml +5 -0
- data/test/fixtures/person.rb +2 -0
- data/test/test_helper.rb +71 -0
- data/test/test_magic_multi_connections.rb +26 -0
- data/test/test_parent_module.rb +18 -0
- data/test/test_preexisting_module.rb +39 -0
- data/website/index.html +340 -0
- data/website/index.txt +223 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +138 -0
- data/website/template.js +3 -0
- data/website/template.rhtml +53 -0
- data/website/version-raw.js +3 -0
- data/website/version-raw.txt +2 -0
- data/website/version.js +4 -0
- data/website/version.txt +3 -0
- metadata +80 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
print "Using native Postgresql\n"
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
ActiveRecord::Base.logger = Logger.new("debug.log")
|
5
|
+
|
6
|
+
db_connection_options = {
|
7
|
+
:adapter => "postgresql",
|
8
|
+
:encoding => "utf8",
|
9
|
+
:database => 'magic_multi_connections_unittest'
|
10
|
+
}
|
11
|
+
|
12
|
+
db_extra_connection_options = {
|
13
|
+
:adapter => "postgresql",
|
14
|
+
:encoding => "utf8",
|
15
|
+
:database => 'magic_multi_connections_extra_unittest'
|
16
|
+
}
|
17
|
+
|
18
|
+
|
19
|
+
ActiveRecord::Base.configurations = { 'production' => db_connection_options, 'contact_repo' => db_extra_connection_options }
|
20
|
+
ActiveRecord::Base.establish_connection(:production)
|
data/test/test_helper.rb
ADDED
@@ -0,0 +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
|
@@ -0,0 +1,26 @@
|
|
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
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
module A
|
4
|
+
module B
|
5
|
+
module C
|
6
|
+
class Z
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
class TestParentModule < Test::Unit::TestCase
|
13
|
+
|
14
|
+
def test_method
|
15
|
+
assert_equal(A::B::C, A::B::C::Z.parent_module)
|
16
|
+
assert_equal(Object, A.parent_module)
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
|
3
|
+
module Preexisting
|
4
|
+
class Person < ActiveRecord::Base
|
5
|
+
end
|
6
|
+
|
7
|
+
Foo = "foo" # just to ensure it doesn't do anything stupid with non-classes
|
8
|
+
|
9
|
+
class NotAciveRecord; end # similarly, this class should be ignored
|
10
|
+
end
|
11
|
+
|
12
|
+
module AnotherPre
|
13
|
+
end
|
14
|
+
|
15
|
+
class TestPreexistingModule < Test::Unit::TestCase
|
16
|
+
|
17
|
+
def setup
|
18
|
+
create_fixtures :people
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_update_existing_classes
|
22
|
+
assert_equal("ActiveRecord::Base", Preexisting::Person.active_connection_name)
|
23
|
+
Preexisting.establish_connection :contact_repo
|
24
|
+
assert_equal("Preexisting::Person", Preexisting::Person.active_connection_name)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Rails can dynamically load classes when requested
|
28
|
+
def test_update_on_load
|
29
|
+
AnotherPre.establish_connection :contact_repo
|
30
|
+
AnotherPre.class_eval <<-EOS
|
31
|
+
class Person < ActiveRecord::Base
|
32
|
+
def tester; end
|
33
|
+
end
|
34
|
+
EOS
|
35
|
+
assert(AnotherPre::Person.instance_methods.include?("tester"), "AnotherPre::Person should include #tester method")
|
36
|
+
assert_equal("AnotherPre::Person", AnotherPre::Person.name)
|
37
|
+
assert_equal("AnotherPre::Person", AnotherPre::Person.active_connection_name)
|
38
|
+
end
|
39
|
+
end
|
data/website/index.html
ADDED
@@ -0,0 +1,340 @@
|
|
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="/">↩ 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>→ Ruby on Rails</h1>
|
39
|
+
|
40
|
+
|
41
|
+
<h1>→ 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 – have 2+ connections open – 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"><</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"># => 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"># => 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 “private” 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>> rails privacy -d sqlite3
|
108
|
+
> cd privacy
|
109
|
+
> ruby script/generate model Person
|
110
|
+
> 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"><</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>> rake db:migrate
|
153
|
+
> 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">></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">>></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">=></span> <span class="punct">'</span><span class="string">Nic</span><span class="punct">')</span>
|
160
|
+
<span class="punct">>></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">=></span> <span class="punct">'</span><span class="string">Banjo</span><span class="punct">')</span>
|
161
|
+
<span class="punct">>></span> <span class="ident">exit</span>
|
162
|
+
<span class="punct">></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">>></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">=></span> <span class="punct">'</span><span class="string">Super Magical Nic</span><span class="punct">')</span>
|
164
|
+
<span class="punct">>></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">"</span><span class="string">magic_multi_connections</span><span class="punct">"</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>> 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"><</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 “private” 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"><h1><%= @mod::Person %></h1>
|
234
|
+
<h2><%= @mod::Person.active_connection_name %></h2>
|
235
|
+
|
236
|
+
<ol>
|
237
|
+
<% @people.each do |person| -%>
|
238
|
+
<li><%= "#{person.name} - #{person.class}" %></li>
|
239
|
+
<% end -%>
|
240
|
+
</ol>
|
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>> 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’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’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"># => "Admin::Page"</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"># => 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"># => { :name => ['Dr Nic', 'Nic'], :age => [32, 20] }</span>
|
297
|
+
</pre></p>
|
298
|
+
|
299
|
+
|
300
|
+
<h2>Dr Nic’s Blog</h2>
|
301
|
+
|
302
|
+
|
303
|
+
<p><a href="http://www.drnicwilliams.com">http://www.drnicwilliams.com</a> – 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>
|