Skip to content

Commit 79ce7d9

Browse files
committed
Deprecate spec_name and use name for configurations
I have so. many. regrets. about using `spec_name` for database configurations and now I'm finally putting this mistake to an end. Back when I started multi-db work I assumed that eventually `connection_specification_name` (sometimes called `spec_name`) and `spec_name` for configurations would one day be the same thing. After 2 years I no longer believe they will ever be the same thing. This PR deprecates `spec_name` on database configurations in favor of `name`. It's the same behavior, just a better name, or at least a less confusing name. `connection_specification_name` refers to the parent class name (ie ActiveRecord::Base, AnimalsBase, etc) that holds the connection for it's models. In some places like ConnectionHandler it shortens this to `spec_name`, hence the major confusion. Recently I've been working with some new folks on database stuff and connection management and realize how confusing it was to explain that `db_config.spec_name` was not `spec_name` and `connection_specification_name`. Worse than that one is a symbole while the other is a class name. This was made even more complicated by the fact that `ActiveRecord::Base` used `primary` as the `connection_specification_name` until rails#38190. After spending 2 years with connection management I don't believe that we can ever use the symbols from the database configs as a way to connect the database without the class name being _somewhere_ because a db_config does not know who it's owner class is until it's been connected and a model has no idea what db_config belongs to it until it's connected. The model is the only way to tie a primary/writer config to a replica/reader config. This could change in the future but I don't see value in adding a class name to the db_configs before connection or telling a model what config belongs to it before connection. That would probably break a lot of application assumptions. If we do ever end up in that world, we can use name, because tbh `spec_name` and `connection_specification_name` were always confusing to me.
1 parent a5cda04 commit 79ce7d9

34 files changed

+293
-244
lines changed

activerecord/CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,23 @@
1+
* Deprecate `spec_name` in favor of `name` on database configurations
2+
3+
The accessors for `spec_name` on `configs_for` and `DatabaseConfig` are deprecated. Please use `name` instead.
4+
5+
Deprecated behavior:
6+
7+
```ruby
8+
db_config = ActiveRecord::Base.configs_for(env_name: "development", spec_name: "primary")
9+
db_config.spec_name
10+
```
11+
12+
New behavior:
13+
14+
```ruby
15+
db_config = ActiveRecord::Base.configs_for(env_name: "development", name: "primary")
16+
db_config.name
17+
```
18+
19+
*Eileen M. Uchitelle*
20+
121
* Add additional database-specific rake tasks for multi-database users
222

323
Previously, `rails db:create`, `rails db:drop`, and `rails db:migrate` were the only rails tasks that could operate on a single

activerecord/lib/active_record/connection_adapters/abstract_adapter.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,12 @@ def migration_context # :nodoc:
130130
def schema_migration # :nodoc:
131131
@schema_migration ||= begin
132132
conn = self
133-
spec_name = conn.pool.db_config.spec_name
134-
name = "#{spec_name}::SchemaMigration"
133+
name = conn.pool.db_config.name
134+
schema_migration_name = "#{name}::SchemaMigration"
135135

136136
Class.new(ActiveRecord::SchemaMigration) do
137-
define_singleton_method(:name) { name }
138-
define_singleton_method(:to_s) { name }
137+
define_singleton_method(:name) { schema_migration_name }
138+
define_singleton_method(:to_s) { schema_migration_name }
139139

140140
connection_handler.connection_pool_names.each do |pool_name|
141141
if conn.pool == connection_handler.retrieve_connection_pool(pool_name)

activerecord/lib/active_record/connection_handling.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ def connection_config
203203
#
204204
# ActiveRecord::Base.connection_db_config
205205
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
206-
# @spec_name="primary", @config={pool: 5, timeout: 5000, database: "db/development.sqlite3", adapter: "sqlite3"}>
206+
# @name="primary", @config={pool: 5, timeout: 5000, database: "db/development.sqlite3", adapter: "sqlite3"}>
207207
#
208208
# Use only for reading.
209209
def connection_db_config

activerecord/lib/active_record/core.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ module Core
4343
#
4444
# #<ActiveRecord::DatabaseConfigurations:0x00007fd1acbdf800 @configurations=[
4545
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",
46-
# @spec_name="primary", @config={adapter: "sqlite3", database: "db/development.sqlite3"}>,
46+
# @name="primary", @config={adapter: "sqlite3", database: "db/development.sqlite3"}>,
4747
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbdea90 @env_name="production",
48-
# @spec_name="primary", @config={adapter: "sqlite3", database: "db/production.sqlite3"}>
48+
# @name="primary", @config={adapter: "sqlite3", database: "db/production.sqlite3"}>
4949
# ]>
5050
def self.configurations=(config)
5151
@@configurations = ActiveRecord::DatabaseConfigurations.new(config)

activerecord/lib/active_record/database_configurations.rb

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,28 @@ def initialize(configurations = {})
2222
# Collects the configs for the environment and optionally the specification
2323
# name passed in. To include replica configurations pass <tt>include_replicas: true</tt>.
2424
#
25-
# If a spec name is provided a single DatabaseConfig object will be
25+
# If a name is provided a single DatabaseConfig object will be
2626
# returned, otherwise an array of DatabaseConfig objects will be
2727
# returned that corresponds with the environment and type requested.
2828
#
2929
# ==== Options
3030
#
3131
# * <tt>env_name:</tt> The environment name. Defaults to +nil+ which will collect
3232
# configs for all environments.
33-
# * <tt>spec_name:</tt> The specification name (i.e. primary, animals, etc.). Defaults
33+
# * <tt>name:</tt> The db name name (i.e. primary, animals, etc.). Defaults
3434
# to +nil+. If no +env_name+ is specified the config for the default env and the
35-
# passed +spec_name+ will be returned.
35+
# passed +name+ will be returned.
3636
# * <tt>include_replicas:</tt> Determines whether to include replicas in
3737
# the returned list. Most of the time we're only iterating over the write
3838
# connection (i.e. migrations don't need to run for the write and read connection).
3939
# Defaults to +false+.
40-
def configs_for(env_name: nil, spec_name: nil, include_replicas: false)
41-
env_name ||= default_env if spec_name
40+
def configs_for(env_name: nil, spec_name: nil, name: nil, include_replicas: false)
41+
if spec_name
42+
name = spec_name
43+
ActiveSupport::Deprecation.warn("The kwarg `spec_name` is deprecated in favor of `name`. `spec_name` will be removed in Rails 6.2")
44+
end
45+
46+
env_name ||= default_env if name
4247
configs = env_with_configs(env_name)
4348

4449
unless include_replicas
@@ -47,9 +52,9 @@ def configs_for(env_name: nil, spec_name: nil, include_replicas: false)
4752
end
4853
end
4954

50-
if spec_name
55+
if name
5156
configs.find do |db_config|
52-
db_config.spec_name == spec_name
57+
db_config.name == name
5358
end
5459
else
5560
configs
@@ -76,7 +81,7 @@ def default_hash(env = default_env)
7681
def find_db_config(env)
7782
configurations.find do |db_config|
7883
db_config.env_name == env.to_s ||
79-
(db_config.for_current_env? && db_config.spec_name == env.to_s)
84+
(db_config.for_current_env? && db_config.name == env.to_s)
8085
end
8186
end
8287

@@ -86,7 +91,7 @@ def to_h
8691
memo.merge(db_config.env_name => db_config.configuration_hash.stringify_keys)
8792
end
8893
end
89-
deprecate to_h: "You can use `ActiveRecord::Base.configurations.configs_for(env_name: 'env', spec_name: 'primary').configuration_hash` to get the configuration hashes."
94+
deprecate to_h: "You can use `ActiveRecord::Base.configurations.configs_for(env_name: 'env', name: 'primary').configuration_hash` to get the configuration hashes."
9095

9196
# Checks if the application's configurations are empty.
9297
#
@@ -174,8 +179,8 @@ def build_configs(configs)
174179
end
175180

176181
def walk_configs(env_name, config)
177-
config.map do |spec_name, sub_config|
178-
build_db_config_from_raw_config(env_name, spec_name.to_s, sub_config)
182+
config.map do |name, sub_config|
183+
build_db_config_from_raw_config(env_name, name.to_s, sub_config)
179184
end
180185
end
181186

@@ -184,7 +189,7 @@ def resolve_symbol_connection(env_name, pool_name)
184189

185190
if db_config
186191
config = db_config.configuration_hash.dup
187-
db_config = DatabaseConfigurations::HashConfig.new(db_config.env_name, db_config.spec_name, config)
192+
db_config = DatabaseConfigurations::HashConfig.new(db_config.env_name, db_config.name, config)
188193
db_config.owner_name = pool_name.to_s
189194
db_config
190195
else
@@ -202,68 +207,68 @@ def build_configuration_sentence
202207
configs = configs_for(include_replicas: true)
203208

204209
configs.group_by(&:env_name).map do |env, config|
205-
namespaces = config.map(&:spec_name)
206-
if namespaces.size > 1
207-
"#{env}: #{namespaces.join(", ")}"
210+
names = config.map(&:name)
211+
if names.size > 1
212+
"#{env}: #{names.join(", ")}"
208213
else
209214
env
210215
end
211216
end.join("\n")
212217
end
213218

214-
def build_db_config_from_raw_config(env_name, spec_name, config)
219+
def build_db_config_from_raw_config(env_name, name, config)
215220
case config
216221
when String
217-
build_db_config_from_string(env_name, spec_name, config)
222+
build_db_config_from_string(env_name, name, config)
218223
when Hash
219-
build_db_config_from_hash(env_name, spec_name, config.symbolize_keys)
224+
build_db_config_from_hash(env_name, name, config.symbolize_keys)
220225
else
221226
raise InvalidConfigurationError, "'{ #{env_name} => #{config} }' is not a valid configuration. Expected '#{config}' to be a URL string or a Hash."
222227
end
223228
end
224229

225-
def build_db_config_from_string(env_name, spec_name, config)
230+
def build_db_config_from_string(env_name, name, config)
226231
url = config
227232
uri = URI.parse(url)
228233
if uri.scheme
229-
UrlConfig.new(env_name, spec_name, url)
234+
UrlConfig.new(env_name, name, url)
230235
else
231236
raise InvalidConfigurationError, "'{ #{env_name} => #{config} }' is not a valid configuration. Expected '#{config}' to be a URL string or a Hash."
232237
end
233238
end
234239

235-
def build_db_config_from_hash(env_name, spec_name, config)
240+
def build_db_config_from_hash(env_name, name, config)
236241
if config.has_key?(:url)
237242
url = config[:url]
238243
config_without_url = config.dup
239244
config_without_url.delete :url
240245

241-
UrlConfig.new(env_name, spec_name, url, config_without_url)
246+
UrlConfig.new(env_name, name, url, config_without_url)
242247
else
243-
HashConfig.new(env_name, spec_name, config)
248+
HashConfig.new(env_name, name, config)
244249
end
245250
end
246251

247252
def merge_db_environment_variables(current_env, configs)
248253
configs.map do |config|
249254
next config if config.is_a?(UrlConfig) || config.env_name != current_env
250255

251-
url_config = environment_url_config(current_env, config.spec_name, config.configuration_hash)
256+
url_config = environment_url_config(current_env, config.name, config.configuration_hash)
252257
url_config || config
253258
end
254259
end
255260

256-
def environment_url_config(env, spec_name, config)
257-
url = environment_value_for(spec_name)
261+
def environment_url_config(env, name, config)
262+
url = environment_value_for(name)
258263
return unless url
259264

260-
UrlConfig.new(env, spec_name, url, config)
265+
UrlConfig.new(env, name, url, config)
261266
end
262267

263-
def environment_value_for(spec_name)
264-
spec_env_key = "#{spec_name.upcase}_DATABASE_URL"
265-
url = ENV[spec_env_key]
266-
url ||= ENV["DATABASE_URL"] if spec_name == "primary"
268+
def environment_value_for(name)
269+
name_env_key = "#{name.upcase}_DATABASE_URL"
270+
url = ENV[name_env_key]
271+
url ||= ENV["DATABASE_URL"] if name == "primary"
267272
url
268273
end
269274

activerecord/lib/active_record/database_configurations/database_config.rb

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@ class DatabaseConfigurations
66
# UrlConfig respectively. It will never return a DatabaseConfig object,
77
# as this is the parent class for the types of database configuration objects.
88
class DatabaseConfig # :nodoc:
9-
attr_reader :env_name, :spec_name
9+
attr_reader :env_name, :name, :spec_name
10+
deprecate :spec_name, "spec_name accessors are deprecated and will be removed in Rails 6.2, please use name instead."
11+
1012
attr_accessor :owner_name
1113

12-
def initialize(env_name, spec_name)
14+
def initialize(env_name, name)
1315
@env_name = env_name
14-
@spec_name = spec_name
16+
@name = name
17+
@spec_name = name
1518
end
1619

1720
def config

activerecord/lib/active_record/database_configurations/hash_config.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,21 @@ class DatabaseConfigurations
1212
# Becomes:
1313
#
1414
# #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10
15-
# @env_name="development", @spec_name="primary", @config={database: "db_name"}>
15+
# @env_name="development", @name="primary", @config={database: "db_name"}>
1616
#
1717
# ==== Options
1818
#
1919
# * <tt>:env_name</tt> - The Rails environment, i.e. "development".
20-
# * <tt>:spec_name</tt> - The specification name. In a standard two-tier
20+
# * <tt>:name</tt> - The specification name. In a standard two-tier
2121
# database configuration this will default to "primary". In a multiple
2222
# database three-tier database configuration this corresponds to the name
2323
# used in the second tier, for example "primary_readonly".
2424
# * <tt>:config</tt> - The config hash. This is the hash that contains the
2525
# database adapter, name, and other important information for database
2626
# connections.
2727
class HashConfig < DatabaseConfig
28-
def initialize(env_name, spec_name, config)
29-
super(env_name, spec_name)
28+
def initialize(env_name, name, config)
29+
super(env_name, name)
3030
@config = config.symbolize_keys
3131
end
3232

activerecord/lib/active_record/database_configurations/url_config.rb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ class DatabaseConfigurations
1313
# Becomes:
1414
#
1515
# #<ActiveRecord::DatabaseConfigurations::UrlConfig:0x00007fdc3238f340
16-
# @env_name="default_env", @spec_name="primary",
16+
# @env_name="default_env", @name="primary",
1717
# @config={adapter: "postgresql", database: "foo", host: "localhost"},
1818
# @url="postgres://localhost/foo">
1919
#
2020
# ==== Options
2121
#
2222
# * <tt>:env_name</tt> - The Rails environment, ie "development".
23-
# * <tt>:spec_name</tt> - The specification name. In a standard two-tier
23+
# * <tt>:name</tt> - The specification name. In a standard two-tier
2424
# database configuration this will default to "primary". In a multiple
2525
# database three-tier database configuration this corresponds to the name
2626
# used in the second tier, for example "primary_readonly".
@@ -31,8 +31,8 @@ class DatabaseConfigurations
3131
class UrlConfig < HashConfig
3232
attr_reader :url
3333

34-
def initialize(env_name, spec_name, url, config = {})
35-
super(env_name, spec_name, config)
34+
def initialize(env_name, name, url, config = {})
35+
super(env_name, name, config)
3636

3737
@url = url
3838
@config.merge!(build_url_hash)

activerecord/lib/active_record/railtie.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ class Railtie < Rails::Railtie # :nodoc:
131131
ActiveSupport.on_load(:active_record) do
132132
db_config = ActiveRecord::Base.configurations.configs_for(
133133
env_name: Rails.env,
134-
spec_name: "primary",
134+
name: "primary",
135135
)
136136
filename = ActiveRecord::Tasks::DatabaseTasks.cache_dump_filename(
137137
"primary",

0 commit comments

Comments
 (0)