From 4f7231da7017a198e5cff4735ffee6c7e5bb36a6 Mon Sep 17 00:00:00 2001 From: Edouard CHIN Date: Wed, 13 Feb 2019 13:00:47 +0100 Subject: Fix the `config_for` to always return a NonSymbolAccessDeprecatedHash: - If you have hashes inside array, the hashes were getting initialized as regular HWIA wereas we want them to be NonSymbolAccessDeprecatedHash in order to trigger a deprecation warning when keys are accessed with string. This patch fixes that by overwriting the `[]=` to to the same as what HWIA does (with the difference that we don't call `convert_key` to not trigger a deprecation when setting value). I also took the liberty to extract `hash.nested_under_indifferent_access`, into a separate method to allow subclasses to return whatever they want. Inheriting HWIA is not common, but I think it's useful for cases like this one where we want to preprocess reading and writing values in the hash (for deprecation purposes or other reasons). --- railties/CHANGELOG.md | 5 +++++ railties/lib/rails/application.rb | 22 ++++++++++++++++++---- railties/test/application/configuration_test.rb | 22 ++++++++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/railties/CHANGELOG.md b/railties/CHANGELOG.md index d66add2ca0..ab3c33728d 100644 --- a/railties/CHANGELOG.md +++ b/railties/CHANGELOG.md @@ -1,3 +1,8 @@ +* Fix `Rails.application.config_for` returning a HWIA when Hash were + inside Array. + + *Edouard Chin* + * Fix non-symbol access to nested hashes returned from `Rails::Application.config_for` being broken by allowing non-symbol access with a deprecation notice. diff --git a/railties/lib/rails/application.rb b/railties/lib/rails/application.rb index d0417f8a49..fbad3e5db3 100644 --- a/railties/lib/rails/application.rb +++ b/railties/lib/rails/application.rb @@ -602,10 +602,7 @@ module Rails end def []=(key, value) - if value.is_a?(Hash) - value = self.class.new(value) - end - super(key.to_sym, value) + regular_writer(key.to_sym, convert_value(value, for: :assignment)) end private @@ -623,6 +620,23 @@ module Rails 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 diff --git a/railties/test/application/configuration_test.rb b/railties/test/application/configuration_test.rb index 960f708bdf..f3161ad2a8 100644 --- a/railties/test/application/configuration_test.rb +++ b/railties/test/application/configuration_test.rb @@ -1787,6 +1787,28 @@ module ApplicationTests 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: -- cgit v1.2.3