Remove deprecated non-symbol access to nested config_for hashes

This commit is contained in:
Étienne Barrié 2019-12-03 15:43:10 -05:00
parent cf27cfa18b
commit e5e9c558a3
4 changed files with 44 additions and 171 deletions

@ -75,6 +75,30 @@ To allow you to upgrade to new defaults one by one, the update task has created
Upgrading from Rails 6.0 to Rails 6.1
-------------------------------------
### `Rails.application.config_for` return value no longer supports access with String keys.
Given a configuration file like this:
```yaml
# config/example.yml
development:
options:
key: value
```
```ruby
Rails.application.config_for(:example).options
```
This used to return a hash on which you could access values with String keys. That was deprecated in 6.0, and now doesn't work anymore.
You can call `with_indifferent_access` on the return value of `config_for` if you still want to access values with String keys, e.g.:
```ruby
Rails.application.config_for(:example).with_indifferent_access.dig('options', 'key')
```
### Response's Content-Type when using `respond_to#any`
The Content-Type header returned in the response can differ from what Rails 6.0 returned,

@ -1,3 +1,20 @@
* Remove access to values in nested hashes returned by `Rails.application.config_for` via String keys.
```yaml
# config/example.yml
development:
options:
key: value
```
```ruby
Rails.application.config_for(:example).options
```
This used to return a Hash on which you could access values with String keys. This was deprecated in 6.0, and now doesn't work anymore.
*Étienne Barrié*
* Configuration files for environments (`config/environments/*.rb`) are
now able to modify `autoload_paths`, `autoload_once_paths`, and
`eager_load_paths`.

@ -228,11 +228,11 @@ def config_for(name, env: Rails.env)
if yaml.exist?
require "erb"
config = YAML.load(ERB.new(yaml.read).result) || {}
config = (config["shared"] || {}).merge(config[env] || {})
config = YAML.load(ERB.new(yaml.read).result, symbolize_names: true) || {}
config = (config[:shared] || {}).merge(config[env.to_sym] || {})
ActiveSupport::OrderedOptions.new.tap do |options|
options.update(NonSymbolAccessDeprecatedHash.new(config))
options.update(config)
end
else
raise "Could not load configuration. No such file - #{yaml}"
@ -604,51 +604,5 @@ def build_request(env)
def build_middleware
config.app_middleware + super
end
class NonSymbolAccessDeprecatedHash < HashWithIndifferentAccess # :nodoc:
def initialize(value = nil)
if value.is_a?(Hash)
value.each_pair { |k, v| self[k] = v }
else
super
end
end
def []=(key, value)
regular_writer(key.to_sym, convert_value(value, for: :assignment))
end
private
def convert_key(key)
unless key.kind_of?(Symbol)
ActiveSupport::Deprecation.warn(<<~MESSAGE.squish)
Accessing hashes returned from config_for by non-symbol keys
is deprecated and will be removed in Rails 6.1.
Use symbols for access instead.
MESSAGE
key = key.to_sym
end
key
end
def convert_value(value, options = {}) # :doc:
if value.is_a? Hash
if options[:for] == :to_hash
value.to_hash
else
self.class.new(value)
end
elsif value.is_a?(Array)
if options[:for] != :assignment || value.frozen?
value = value.dup
end
value.map! { |e| convert_value(e, options) }
else
value
end
end
end
end
end

@ -1934,47 +1934,6 @@ class D < C
assert_equal 1, Rails.application.config.my_custom_config[:foo][:bar][:baz]
end
test "config_for loads nested custom configuration from yaml with deprecated non-symbol access" do
app_file "config/custom.yml", <<-RUBY
development:
foo:
bar:
baz: 1
RUBY
add_to_config <<-RUBY
config.my_custom_config = config_for('custom')
RUBY
app "development"
assert_deprecated do
assert_equal 1, Rails.application.config.my_custom_config["foo"]["bar"]["baz"]
end
end
test "config_for loads nested custom configuration inside array from yaml with deprecated non-symbol access" do
app_file "config/custom.yml", <<-RUBY
development:
foo:
bar:
- baz: 1
RUBY
add_to_config <<-RUBY
config.my_custom_config = config_for('custom')
RUBY
app "development"
config = Rails.application.config.my_custom_config
assert_instance_of Rails::Application::NonSymbolAccessDeprecatedHash, config[:foo][:bar].first
assert_deprecated do
assert_equal 1, config[:foo][:bar].first["baz"]
end
end
test "config_for makes all hash methods available" do
app_file "config/custom.yml", <<-RUBY
development:
@ -1999,87 +1958,6 @@ class D < C
assert_equal({ baz: 1 }, actual[:bar])
end
test "config_for generates deprecation notice when nested hash methods are called with non-symbols" do
app_file "config/custom.yml", <<-RUBY
development:
foo:
bar: 1
baz: 2
qux:
boo: 3
RUBY
app "development"
actual = Rails.application.config_for("custom")[:foo]
# slice
assert_deprecated do
assert_equal({ bar: 1, baz: 2 }, actual.slice("bar", "baz"))
end
# except
assert_deprecated do
assert_equal({ qux: { boo: 3 } }, actual.except("bar", "baz"))
end
# dig
assert_deprecated do
assert_equal(3, actual.dig("qux", "boo"))
end
# fetch - hit
assert_deprecated do
assert_equal(1, actual.fetch("bar", 0))
end
# fetch - miss
assert_deprecated do
assert_equal(0, actual.fetch("does-not-exist", 0))
end
# fetch_values
assert_deprecated do
assert_equal([1, 2], actual.fetch_values("bar", "baz"))
end
# key? - hit
assert_deprecated do
assert(actual.key?("bar"))
end
# key? - miss
assert_deprecated do
assert_not(actual.key?("does-not-exist"))
end
# slice!
actual = Rails.application.config_for("custom")[:foo]
assert_deprecated do
slice = actual.slice!("bar", "baz")
assert_equal({ bar: 1, baz: 2 }, actual)
assert_equal({ qux: { boo: 3 } }, slice)
end
# extract!
actual = Rails.application.config_for("custom")[:foo]
assert_deprecated do
extracted = actual.extract!("bar", "baz")
assert_equal({ bar: 1, baz: 2 }, extracted)
assert_equal({ qux: { boo: 3 } }, actual)
end
# except!
actual = Rails.application.config_for("custom")[:foo]
assert_deprecated do
actual.except!("bar", "baz")
assert_equal({ qux: { boo: 3 } }, actual)
end
end
test "config_for uses the Pathname object if it is provided" do
app_file "config/custom.yml", <<-RUBY
development: