db-charmer 1.4.0 → 1.4.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.
- data/README.rdoc +89 -63
- data/VERSION +1 -1
- data/db-charmer.gemspec +2 -2
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
1. Allows you to easily manage AR models' connections (+switch_connection_to+ method)
|
6
6
|
2. Allows you to switch AR models' default connections to a separate servers/databases
|
7
|
-
3. Allows you to easily choose where your query should go (<tt>Model.
|
7
|
+
3. Allows you to easily choose where your query should go (<tt>Model.on_*</tt> methods family)
|
8
8
|
4. Allows you to automatically send read queries to your slaves while masters would handle all the updates.
|
9
9
|
5. Adds multiple databases migrations to ActiveRecord
|
10
10
|
|
@@ -12,13 +12,12 @@
|
|
12
12
|
== Installation
|
13
13
|
|
14
14
|
There are two options when approaching db-charmer installation:
|
15
|
-
* using gem (recommended)
|
15
|
+
* using the gem (recommended)
|
16
16
|
* install as a Rails plugin
|
17
17
|
|
18
18
|
To install as a gem, add this to your environment.rb:
|
19
19
|
|
20
|
-
config.gem '
|
21
|
-
:source => 'http://gems.github.com'
|
20
|
+
config.gem 'db-charmer', :lib => 'db_charmer', :source => 'http://gemcutter.org'
|
22
21
|
|
23
22
|
And then run the command:
|
24
23
|
|
@@ -31,8 +30,8 @@ To install db-charmer as a Rails plugin use this:
|
|
31
30
|
|
32
31
|
== Easy ActiveRecord Connection Management
|
33
32
|
|
34
|
-
As a part of this plugin we've added +switch_connection_to+ method that accepts many different kinds
|
35
|
-
of db connections and uses them on a model. We support:
|
33
|
+
As a part of this plugin we've added +switch_connection_to+ method that accepts many different kinds
|
34
|
+
of db connections specifications and uses them on a model. We support:
|
36
35
|
|
37
36
|
1. Strings and symbols as the names of connection configuration blocks in database.yml.
|
38
37
|
2. ActiveRecord models (we'd use connection currently set up on a model).
|
@@ -42,32 +41,33 @@ of db connections and uses them on a model. We support:
|
|
42
41
|
Sample code:
|
43
42
|
|
44
43
|
class Foo < ActiveRecord::Model; end
|
45
|
-
|
44
|
+
|
46
45
|
Foo.switch_connection_to(:blah)
|
47
46
|
Foo.switch_connection_to('foo')
|
48
47
|
Foo.switch_connection_to(Bar)
|
49
48
|
Foo.switch_connection_to(Baz.connection)
|
50
49
|
Foo.switch_connection_to(nil)
|
51
50
|
|
52
|
-
The +switch_connection_to+ method has an optional second parameter +should_exist+ which is true
|
53
|
-
by default. This parameter is used when the method is called with a string or a symbol connection
|
54
|
-
name and there is no such connection configuration in the database.yml file. If this parameter
|
55
|
-
is true
|
56
|
-
change would happen.
|
57
|
-
|
58
|
-
|
51
|
+
The +switch_connection_to+ method has an optional second parameter +should_exist+ which is true
|
52
|
+
by default. This parameter is used when the method is called with a string or a symbol connection
|
53
|
+
name and there is no such connection configuration in the database.yml file. If this parameter
|
54
|
+
is +true+, an exception would be raised, otherwise, the error would be ignored and no connection
|
55
|
+
change would happen.
|
56
|
+
|
57
|
+
This is really useful when in development mode or in a tests you do not want to create many different
|
58
|
+
databases on your local machine and just want to put all your tables in a single database.
|
59
59
|
|
60
|
-
Warning
|
61
|
-
method called on. You can't call the +switch_connection_to+ method and switch connection for a
|
62
|
-
base class in some hierarchy (for example, you can't switch AR::Base connection and see all your
|
63
|
-
models switched to the new connection, use classic +establish_connection+ instead).
|
60
|
+
*Warning*: All the connection switching calls would switch connection *only* for those classes the
|
61
|
+
method called on. You can't call the +switch_connection_to+ method and switch connection for a
|
62
|
+
base class in some hierarchy (for example, you can't switch AR::Base connection and see all your
|
63
|
+
models switched to the new connection, use the classic +establish_connection+ instead).
|
64
64
|
|
65
65
|
|
66
66
|
== Multiple DB Migrations
|
67
67
|
|
68
|
-
In every application that works with many databases, there is need in convenient schema migrations mechanism.
|
68
|
+
In every application that works with many databases, there is need in a convenient schema migrations mechanism.
|
69
69
|
|
70
|
-
All Rails users already have this mechanism - rails migrations. So in +DbCharmer+, we've made it possible
|
70
|
+
All Rails users already have this mechanism - rails migrations. So in +DbCharmer+, we've made it possible
|
71
71
|
to seamlessly use multiple databases in Rails migrations.
|
72
72
|
|
73
73
|
There are two methods available in migrations to operate on more than one database:
|
@@ -79,14 +79,14 @@ Migration class example (global connection rewrite):
|
|
79
79
|
|
80
80
|
class MultiDbTest < ActiveRecord::Migration
|
81
81
|
db_magic :connection => :second_db
|
82
|
-
|
82
|
+
|
83
83
|
def self.up
|
84
84
|
create_table :test_table, :force => true do |t|
|
85
85
|
t.string :test_string
|
86
86
|
t.timestamps
|
87
87
|
end
|
88
88
|
end
|
89
|
-
|
89
|
+
|
90
90
|
def self.down
|
91
91
|
drop_table :test_table
|
92
92
|
end
|
@@ -103,39 +103,40 @@ Migration class example (block-level connection rewrite):
|
|
103
103
|
end
|
104
104
|
end
|
105
105
|
end
|
106
|
-
|
106
|
+
|
107
107
|
def self.down
|
108
108
|
on_db :second_db { drop_table :test_table }
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
112
112
|
|
113
|
-
By default in development and test environments you could skip this <tt>:second_db</tt>
|
114
|
-
connection from your database.yml files
|
115
|
-
get the table created on a separate server and/or in a
|
113
|
+
By default in development and test environments you could skip this <tt>:second_db</tt>
|
114
|
+
connection from your database.yml files and rails would create the tables in your single database,
|
115
|
+
but in production you'd specify it and get the table created on a separate server and/or in a
|
116
|
+
separate database.
|
116
117
|
|
117
|
-
This behaviour is controlled by the <tt>DbCharmer.migration_connections_should_exist</tt>
|
118
|
+
This behaviour is controlled by the <tt>DbCharmer.migration_connections_should_exist</tt>
|
118
119
|
configuration attribute which could be set from a rails initializer.
|
119
120
|
|
120
121
|
|
121
122
|
== Using Models in Master-Slave Environments
|
122
123
|
|
123
|
-
Master-slave replication is the most popular scale-out technique in medium and
|
124
|
-
database applications today. There are some rails plugins out there that help
|
125
|
-
developers to use slave servers in their models but none of
|
124
|
+
Master-slave replication is the most popular scale-out technique in a medium-sized and
|
125
|
+
large database-centric applications today. There are some rails plugins out there that help
|
126
|
+
developers to use slave servers in their models but none of them were flexible enough
|
126
127
|
for us to start using them in a huge application we work on.
|
127
128
|
|
128
|
-
So, we've been using ActsAsReadonlyable plugin for a long time and have
|
129
|
-
|
130
|
-
by its authors, we've decided to collect all of our master-slave code in one plugin
|
129
|
+
So, we've been using ActsAsReadonlyable plugin for a long time and have made tons
|
130
|
+
of changes in its code over the time. But since that plugin has been abandoned
|
131
|
+
by its authors, we've decided to collect all of our master-slave code in one plugin
|
131
132
|
and release it for rails 2.2+. +DbCharmer+ adds the following features to Rails models:
|
132
133
|
|
133
134
|
|
134
|
-
=== Auto-Switching all Reads to Slave(s)
|
135
|
+
=== Auto-Switching all Reads to the Slave(s)
|
135
136
|
|
136
|
-
When you create a model, you could use <tt>db_magic :slave => :blah</tt> or
|
137
|
-
<tt>db_magic :slaves => [ :foo, :bar ]</tt> commands in your model to set up reads
|
138
|
-
redirection mode when all your find/count/exist/etc methods will be reading data
|
137
|
+
When you create a model, you could use <tt>db_magic :slave => :blah</tt> or
|
138
|
+
<tt>db_magic :slaves => [ :foo, :bar ]</tt> commands in your model to set up reads
|
139
|
+
redirection mode when all your find/count/exist/etc methods will be reading data
|
139
140
|
from your slave (or a bunch of slaves in a round-robin manner). Here is an example:
|
140
141
|
|
141
142
|
class Foo < ActiveRecord::Base
|
@@ -149,16 +150,16 @@ from your slave (or a bunch of slaves in a round-robin manner). Here is an examp
|
|
149
150
|
|
150
151
|
=== Default Connection Switching
|
151
152
|
|
152
|
-
If you have more than one master-slave cluster (or simply more than one database)
|
153
|
-
in your database environment, then you might want to change the default database
|
154
|
-
connection of some of your models. You could do that by using
|
153
|
+
If you have more than one master-slave cluster (or simply more than one database)
|
154
|
+
in your database environment, then you might want to change the default database
|
155
|
+
connection of some of your models. You could do that by using
|
155
156
|
<tt>db_magic :connection => :foo</tt> call from your models. Example:
|
156
157
|
|
157
158
|
class Foo < ActiveRecord::Base
|
158
159
|
db_magic :connection => :foo
|
159
160
|
end
|
160
161
|
|
161
|
-
Sample model on a separate master-slave cluster (so, separate main connection +
|
162
|
+
Sample model on a separate master-slave cluster (so, separate main connection +
|
162
163
|
a slave connection):
|
163
164
|
|
164
165
|
class Bar < ActiveRecord::Base
|
@@ -167,12 +168,12 @@ a slave connection):
|
|
167
168
|
|
168
169
|
=== Per-Query Connection Management
|
169
170
|
|
170
|
-
Sometimes you have
|
171
|
-
This could happen for example when you have just added some data and need to read
|
172
|
-
it back and not sure if it made it all the way to the slave yet or no. For this
|
173
|
-
situation
|
171
|
+
Sometimes you have select queries that you know you want to run on the master.
|
172
|
+
This could happen for example when you have just added some data and need to read
|
173
|
+
it back and not sure if it made it all the way to the slave yet or no. For this
|
174
|
+
situation and a few others there is a set of methods we've added to ActiveRecord models:
|
174
175
|
|
175
|
-
1) +on_master+ - this method could be used in two forms: block form and proxy form.
|
176
|
+
1) +on_master+ - this method could be used in two forms: block form and proxy form.
|
176
177
|
In the block form you could force connection switch for a block of code:
|
177
178
|
|
178
179
|
User.on_master do
|
@@ -180,22 +181,22 @@ In the block form you could force connection switch for a block of code:
|
|
180
181
|
user.update_attributes!(:activated => true)
|
181
182
|
end
|
182
183
|
|
183
|
-
In the proxy form this method could be used to force one query to be performed on
|
184
|
+
In the proxy form this method could be used to force one query to be performed on
|
184
185
|
the master database server:
|
185
186
|
|
186
187
|
Comment.on_master.last(:limit => 5)
|
187
188
|
User.on_master.find_by_activation_code(code)
|
188
189
|
User.on_master.exists?(:login => login, :password => password)
|
189
190
|
|
190
|
-
2) +on_slave+ - this method is used to force a query to be run on a slave even in
|
191
|
-
situations when it's been previously forced to use the master. If there is more
|
192
|
-
than one slave, one would be selected randomly. Tis method has two forms as
|
191
|
+
2) +on_slave+ - this method is used to force a query to be run on a slave even in
|
192
|
+
situations when it's been previously forced to use the master. If there is more
|
193
|
+
than one slave, one would be selected randomly. Tis method has two forms as
|
193
194
|
well: block and proxy.
|
194
195
|
|
195
|
-
3) <tt>on_db(connection)</tt> - this method is what makes two previous methods
|
196
|
-
It is used to switch a model's connection to some db for a short block
|
197
|
-
or even for one statement (two forms). It accepts the same range of values
|
198
|
-
the +switch_connection_to+ method does. Example:
|
196
|
+
3) <tt>on_db(connection)</tt> - this method is what makes two previous methods
|
197
|
+
possible. It is used to switch a model's connection to some db for a short block
|
198
|
+
of code or even for one statement (two forms). It accepts the same range of values
|
199
|
+
as the +switch_connection_to+ method does. Example:
|
199
200
|
|
200
201
|
Comment.on_db(:olap).count
|
201
202
|
Post.on_db(:foo).find(:first)
|
@@ -203,14 +204,14 @@ the +switch_connection_to+ method does. Example:
|
|
203
204
|
|
204
205
|
=== Associations Connection Management
|
205
206
|
|
206
|
-
ActiveRecord models can have associations
|
207
|
-
pretty hard to manage connections in chained calls
|
208
|
-
class-only connection switching methods this call
|
209
|
-
want to count posts on a separate database:
|
207
|
+
ActiveRecord models can have an associations with each other and since every model has its
|
208
|
+
own database connections, it becomes pretty hard to manage connections in a chained calls
|
209
|
+
like <tt>User.posts.count</tt>. With a class-only connection switching methods this call
|
210
|
+
would look like the following if we'd want to count posts on a separate database:
|
210
211
|
|
211
212
|
Post.on_db(:olap) { User.posts.count }
|
212
213
|
|
213
|
-
Apparently this is not the best way to write the code and we've implemented <tt>on_*</tt>
|
214
|
+
Apparently this is not the best way to write the code and we've implemented an <tt>on_*</tt>
|
214
215
|
methods on associations as well so you could do things like this:
|
215
216
|
|
216
217
|
@user.posts.on_db(:olap).count
|
@@ -224,18 +225,43 @@ chained methods:
|
|
224
225
|
@photo.owner.on_slave - would return photo's owner
|
225
226
|
|
226
227
|
|
228
|
+
Starting with +DbCharmer+ release 1.4 it is possible to use prefix notation for has_many
|
229
|
+
and HABTM associations connection switching:
|
230
|
+
|
231
|
+
@user.on_db(:foo).posts
|
232
|
+
@user.on_slave.posts
|
233
|
+
|
234
|
+
|
235
|
+
=== Named Scopes Support
|
236
|
+
|
237
|
+
To make it easier for +DbCharmer+ users to use connections switching methods with named scopes,
|
238
|
+
we've added <tt>on_*</tt> methods support on the scopes as well. All the following scope chains
|
239
|
+
would do exactly the same way (the query would be executed on the :foo database connection):
|
240
|
+
|
241
|
+
Post.on_db(:foo).published.with_comments.spam_marked.count
|
242
|
+
Post.published.on_db(:foo).with_comments.spam_marked.count
|
243
|
+
Post.published.with_comments.on_db(:foo).spam_marked.count
|
244
|
+
Post.published.with_comments.spam_marked.on_db(:foo).count
|
245
|
+
|
246
|
+
And now, add this feature to our associations support and here is what we could do:
|
247
|
+
|
248
|
+
@user.on_db(:archive).posts.published.all
|
249
|
+
@user.posts.on_db(:olap).published.count
|
250
|
+
@user.posts.published.on_db(:foo).first
|
251
|
+
|
252
|
+
|
227
253
|
== Documentation
|
228
254
|
|
229
255
|
For more information on the plugin internals, please check out the source code. All the plugin's
|
230
|
-
code is covered with tests that were placed in a separate staging rails project located
|
231
|
-
http://github.com/kovyrin/db-charmer-sandbox. The project has unit tests for all or at least the
|
256
|
+
code is ~100% covered with a tests that were placed in a separate staging rails project located
|
257
|
+
at http://github.com/kovyrin/db-charmer-sandbox. The project has unit tests for all or at least the
|
232
258
|
most of the parts of plugin's code.
|
233
259
|
|
234
260
|
|
235
261
|
== What Ruby and Rails implementations does it work for?
|
236
262
|
|
237
|
-
We
|
238
|
-
with MRI 1.8.6 and Rails 2.2.
|
263
|
+
We have a continuous integration setups for this plugin on MRI 1.8.6 with Rails 2.2 and 2.3.
|
264
|
+
We use the plugin in production on Scribd.com with MRI (rubyee) 1.8.6 and Rails 2.2.
|
239
265
|
|
240
266
|
|
241
267
|
== Who are the authors?
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.4.
|
1
|
+
1.4.1
|
data/db-charmer.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{db-charmer}
|
8
|
-
s.version = "1.4.
|
8
|
+
s.version = "1.4.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Alexey Kovyrin"]
|
12
|
-
s.date = %q{2009-11-
|
12
|
+
s.date = %q{2009-11-03}
|
13
13
|
s.description = %q{ActiveRecord Connections Magic (slaves, multiple connections, etc)}
|
14
14
|
s.email = %q{alexey@kovyrin.net}
|
15
15
|
s.extra_rdoc_files = [
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: db-charmer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexey Kovyrin
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-11-
|
12
|
+
date: 2009-11-03 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|