Skip to content

Commit f53d020

Browse files
committed
Copy-edit pass on the multiple databases guide
Main points: * Applies our documentation guidelines (names of files, punctuation in comments, etc.) * AnimalsRecord was introduced before the primary abstract class. Before this point, stuff related to the primary database is explained first, and then you go for the extra database. This is the natural order, I think. I reordered for consistency. * PrimaryApplicationRecord was missing connects_to. * Fixes parent class for the example related to PrimaryApplicationRecord.
1 parent 2514bde commit f53d020

File tree

1 file changed

+76
-56
lines changed

1 file changed

+76
-56
lines changed

guides/source/active_record_multiple_databases.md

Lines changed: 76 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ Let's say we have an application with a single writer database, and we need to a
3939
new database for some new tables we're adding. The name of the new database will be
4040
"animals".
4141

42-
The `database.yml` looks like this:
42+
`config/database.yml` looks like this:
4343

4444
```yaml
4545
production:
@@ -49,15 +49,15 @@ production:
4949
password: <%= ENV['ROOT_PASSWORD'] %>
5050
```
5151
52-
Let's add a second database called animals and replicas for both databases as well. To do
53-
this, we need to change our `database.yml` from a 2-tier
54-
to a 3-tier config.
52+
Let's add a second database called "animals" and replicas for both databases as
53+
well. To do this, we need to change our `config/database.yml` from a 2-tier to a
54+
3-tier config.
5555

56-
If a primary configuration is provided, it will be used as the "default" configuration. If
57-
there is no configuration named `"primary"`, Rails will use the first configuration as default
56+
If a `primary` configuration key is provided, it will be used as the "default" configuration. If
57+
there is no configuration named `primary`, Rails will use the first configuration as default
5858
for each environment. The default configurations will use the default Rails filenames. For example,
59-
primary configurations will use `schema.rb` for the schema file, whereas all the other entries
60-
will use `[CONFIGURATION_NAMESPACE]_schema.rb` for the filename.
59+
primary configurations will use `db/schema.rb` for the schema file, whereas all the other entries
60+
will use `db/[CONFIGURATION_NAMESPACE]_schema.rb` for the filename.
6161

6262
```yaml
6363
production:
@@ -88,35 +88,26 @@ production:
8888

8989
When using multiple databases, there are a few important settings.
9090

91-
First, the database name for the `primary` and `primary_replica` should be the same because they contain
91+
First, the database name for `primary` and `primary_replica` should be the same because they contain
9292
the same data. This is also the case for `animals` and `animals_replica`.
9393

9494
Second, the username for the writers and replicas should be different, and the
9595
replica user's database permissions should be set to only read and not write.
9696

97-
When using a replica database, you need to add a `replica: true` entry to the replica in the
98-
`database.yml`. This is because Rails otherwise has no way of knowing which one is a replica
97+
When using a replica database, you need to add a `replica: true` entry to the replica in
98+
`config/database.yml`. This is because Rails otherwise has no way of knowing which one is a replica
9999
and which one is the writer. Rails will not run certain tasks, such as migrations, against replicas.
100100

101-
Lastly, for new writer databases, you need to set the `migrations_paths` to the directory
101+
Lastly, for new writer databases, you need to set the `migrations_paths` key to the directory
102102
where you will store migrations for that database. We'll look more at `migrations_paths`
103103
later on in this guide.
104104

105105
You can also configure the schema dump file by setting `schema_dump` to a custom schema file name
106106
or completely skip the schema dumping by setting `schema_dump: false`.
107107

108-
Now that we have a new database, let's set up the connection model. In order to use the
109-
new database we need to create a new abstract class and connect to the animals databases.
108+
Now that we have a new database, let's set up the connection model.
110109

111-
```ruby
112-
class AnimalsRecord < ApplicationRecord
113-
self.abstract_class = true
114-
115-
connects_to database: { writing: :animals, reading: :animals_replica }
116-
end
117-
```
118-
119-
Then we need to update `ApplicationRecord` to be aware of our new replica.
110+
The primary database replica may be configured in `ApplicationRecord` this way:
120111

121112
```ruby
122113
class ApplicationRecord < ActiveRecord::Base
@@ -133,18 +124,39 @@ should share a connection with.
133124
```ruby
134125
class PrimaryApplicationRecord < ActiveRecord::Base
135126
primary_abstract_class
127+
128+
connects_to database: { writing: :primary, reading: :primary_replica }
136129
end
137130
```
138131

139-
Classes that connect to primary/primary_replica can inherit from your primary abstract
140-
class like standard Rails applications:
132+
In that case, classes that connect to `primary`/`primary_replica` can inherit
133+
from your primary abstract class like standard Rails applications do with
134+
`ApplicationRecord`:
141135

142136
```ruby
143-
class Person < ApplicationRecord
137+
class Person < PrimaryApplicationRecord
144138
end
145139
```
146140

147-
By default Rails expects the database roles to be `writing` and `reading` for the primary
141+
On the other hand, we need to setup our models persisted in the "animals" database:
142+
143+
```ruby
144+
class AnimalsRecord < ApplicationRecord
145+
self.abstract_class = true
146+
147+
connects_to database: { writing: :animals, reading: :animals_replica }
148+
end
149+
```
150+
151+
Those models should inherit from that common abstract class:
152+
153+
```ruby
154+
class Car < AnimalsRecord
155+
# Talks automatically to the animals database.
156+
end
157+
```
158+
159+
By default, Rails expects the database roles to be `writing` and `reading` for the primary
148160
and replica respectively. If you have a legacy system you may already have roles set up that
149161
you don't want to change. In that case you can set a new role name in your application config.
150162

@@ -159,8 +171,9 @@ clients have a limit to the number of open connections there can be, and if you
159171
multiply the number of connections you have since Rails uses the model class name for the
160172
connection specification name.
161173

162-
Now that we have the `database.yml` and the new model set up, it's time to create the databases.
163-
Rails ships with all the commands you need to use multiple databases.
174+
Now that we have the `config/database.yml` and the new model set up, it's time
175+
to create the databases. Rails ships with all the commands you need to use
176+
multiple databases.
164177

165178
You can run `bin/rails --help` to see all the commands you're able to run. You should see the following:
166179

@@ -225,8 +238,8 @@ production:
225238
Migrations for multiple databases should live in their own folders prefixed with the
226239
name of the database key in the configuration.
227240

228-
You also need to set the `migrations_paths` in the database configurations to tell Rails
229-
where to find the migrations.
241+
You also need to set `migrations_paths` in the database configurations to tell
242+
Rails where to find the migrations.
230243

231244
For example the `animals` database would look for migrations in the `db/animals_migrate` directory and
232245
`primary` would look in `db/migrate`. Rails generators now take a `--database` option
@@ -243,8 +256,8 @@ class for you. Simply pass the database key to the command line.
243256
$ bin/rails generate scaffold Dog name:string --database animals
244257
```
245258

246-
A class with the database name and `Record` will be created. In this example
247-
the database is `Animals` so we end up with `AnimalsRecord`:
259+
A class with the camelized database name and `Record` will be created. In this
260+
example the database is "animals" so we end up with `AnimalsRecord`:
248261

249262
```ruby
250263
class AnimalsRecord < ApplicationRecord
@@ -264,8 +277,8 @@ end
264277
NOTE: Since Rails doesn't know which database is the replica for your writer you will need to
265278
add this to the abstract class after you're done.
266279

267-
Rails will only generate the new class once. It will not be overwritten by new scaffolds
268-
or deleted if the scaffold is deleted.
280+
Rails will only generate `AnimalsRecord` once. It will not be overwritten by new
281+
scaffolds or deleted if the scaffold is deleted.
269282

270283
If you already have an abstract class and its name differs from `AnimalsRecord`, you can pass
271284
the `--parent` option to indicate you want a different abstract class:
@@ -366,7 +379,7 @@ need.
366379

367380
```ruby
368381
ActiveRecord::Base.connected_to(role: :reading) do
369-
# all code in this block will be connected to the reading role
382+
# All code in this block will be connected to the reading role.
370383
end
371384
```
372385

@@ -381,11 +394,11 @@ like `connected_to(role: :nonexistent)` you will get an error that says
381394

382395
If you want Rails to ensure any queries performed are read only, pass `prevent_writes: true`.
383396
This just prevents queries that look like writes from being sent to the database.
384-
You should also configure your replica database to run in readonly mode.
397+
You should also configure your replica database to run in read-only mode.
385398

386399
```ruby
387400
ActiveRecord::Base.connected_to(role: :reading, prevent_writes: true) do
388-
# Rails will check each query to ensure it's a read query
401+
# Rails will check each query to ensure it's a read query.
389402
end
390403
```
391404

@@ -474,7 +487,7 @@ role and the shard with the `connected_to` API.
474487

475488
```ruby
476489
ActiveRecord::Base.connected_to(role: :reading, shard: :shard_one) do
477-
Person.first # Lookup record from read replica of shard one
490+
Person.first # Lookup record from read replica of shard one.
478491
end
479492
```
480493

@@ -483,12 +496,12 @@ end
483496
Applications are able to automatically switch shards per request using the provided
484497
middleware.
485498

486-
The `ShardSelector` Middleware provides a framework for automatically
499+
The `ShardSelector` middleware provides a framework for automatically
487500
swapping shards. Rails provides a basic framework to determine which
488501
shard to switch to and allows for applications to write custom strategies
489502
for swapping if needed.
490503

491-
The `ShardSelector` takes a set of options (currently only `lock` is supported)
504+
`ShardSelector` takes a set of options (currently only `lock` is supported)
492505
that can be used by the middleware to alter behavior. `lock` is
493506
true by default and will prohibit the request from switching shards once
494507
inside the block. If `lock` is false, then shard swapping will be allowed.
@@ -502,7 +515,7 @@ automatic shard swapping:
502515
$ bin/rails g active_record:multi_db
503516
```
504517

505-
Then in the file uncomment the following:
518+
Then in the generated `config/initializers/multi_db.rb` uncomment the following:
506519

507520
```ruby
508521
Rails.application.configure do
@@ -524,8 +537,8 @@ config.active_record.shard_resolver = ->(request) {
524537

525538
## Granular Database Connection Switching
526539

527-
In Rails 6.1 it's possible to switch connections for one database instead of
528-
all databases globally.
540+
Starting from Rails 6.1, it's possible to switch connections for one database
541+
instead of all databases globally.
529542

530543
With granular database connection switching, any abstract connection class
531544
will be able to switch connections without affecting other connections. This
@@ -534,27 +547,30 @@ while ensuring your `ApplicationRecord` queries go to the primary.
534547

535548
```ruby
536549
AnimalsRecord.connected_to(role: :reading) do
537-
Dog.first # Reads from animals_replica
538-
Person.first # Reads from primary
550+
Dog.first # Reads from animals_replica.
551+
Person.first # Reads from primary.
539552
end
540553
```
541554

542555
It's also possible to swap connections granularly for shards.
543556

544557
```ruby
545558
AnimalsRecord.connected_to(role: :reading, shard: :shard_one) do
546-
Dog.first # Will read from shard_one_replica. If no connection exists for shard_one_replica,
547-
# a ConnectionNotEstablished error will be raised
548-
Person.first # Will read from primary writer
559+
# Will read from shard_one_replica. If no connection exists for shard_one_replica,
560+
# a ConnectionNotEstablished error will be raised.
561+
Dog.first
562+
563+
# Will read from primary writer.
564+
Person.first
549565
end
550566
```
551567

552568
To switch only the primary database cluster use `ApplicationRecord`:
553569

554570
```ruby
555571
ApplicationRecord.connected_to(role: :reading, shard: :shard_one) do
556-
Person.first # Reads from primary_shard_one_replica
557-
Dog.first # Reads from animals_primary
572+
Person.first # Reads from primary_shard_one_replica.
573+
Dog.first # Reads from animals_primary.
558574
end
559575
```
560576

@@ -619,13 +635,17 @@ There are some important things to be aware of with this option:
619635

620636
### Schema Caching
621637

622-
If you want to load a schema cache for each database you must set a `schema_cache_path` in each database configuration and set `config.active_record.lazily_load_schema_cache = true` in your application configuration. Note that this will lazily load the cache when the database connections are established.
638+
If you want to load a schema cache for each database you must set
639+
`schema_cache_path` in each database configuration and set
640+
`config.active_record.lazily_load_schema_cache = true` in your application
641+
configuration. Note that this will lazily load the cache when the database
642+
connections are established.
623643

624644
## Caveats
625645

626646
### Load Balancing Replicas
627647

628-
Rails also doesn't support automatic load balancing of replicas. This is very
629-
dependent on your infrastructure. We may implement basic, primitive load balancing
630-
in the future, but for an application at scale this should be something your application
631-
handles outside of Rails.
648+
Rails doesn't support automatic load balancing of replicas. This is very
649+
dependent on your infrastructure. We may implement basic, primitive load
650+
balancing in the future, but for an application at scale this should be
651+
something your application handles outside of Rails.

0 commit comments

Comments
 (0)