diff options
-rw-r--r-- | actionpack/CHANGELOG.md | 4 | ||||
-rw-r--r-- | actionpack/lib/action_controller/metal/strong_parameters.rb | 17 | ||||
-rw-r--r-- | actionpack/test/controller/parameters/accessors_test.rb | 9 | ||||
-rw-r--r-- | actionpack/test/controller/parameters/mutators_test.rb | 9 | ||||
-rw-r--r-- | activerecord/lib/active_record/associations/collection_proxy.rb | 2 | ||||
-rw-r--r-- | activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb | 10 | ||||
-rw-r--r-- | activerecord/test/cases/calculations_test.rb | 15 | ||||
-rw-r--r-- | activerecord/test/cases/relations_test.rb | 2 | ||||
-rw-r--r-- | guides/source/engines.md | 57 |
9 files changed, 81 insertions, 44 deletions
diff --git a/actionpack/CHANGELOG.md b/actionpack/CHANGELOG.md index 32721ac233..a84f72eca9 100644 --- a/actionpack/CHANGELOG.md +++ b/actionpack/CHANGELOG.md @@ -1,3 +1,7 @@ +* Added `deep_transform_keys` and `deep_transform_keys!` methods to ActionController::Parameters. + + *Gustavo Gutierrez* + * Calling `ActionController::Parameters#transform_keys/!` without a block now returns an enumerator for the parameters instead of the underlying hash. diff --git a/actionpack/lib/action_controller/metal/strong_parameters.rb b/actionpack/lib/action_controller/metal/strong_parameters.rb index 016a633f71..6a07a73d94 100644 --- a/actionpack/lib/action_controller/metal/strong_parameters.rb +++ b/actionpack/lib/action_controller/metal/strong_parameters.rb @@ -693,6 +693,23 @@ module ActionController self end + # Returns a new <tt>ActionController::Parameters</tt> instance with the + # results of running +block+ once for every key. This includes the keys + # from the root hash and from all nested hashes and arrays. The values are unchanged. + def deep_transform_keys(&block) + new_instance_with_inherited_permitted_status( + @parameters.deep_transform_keys(&block) + ) + end + + # Returns the <tt>ActionController::Parameters</tt> instance changing its keys. + # This includes the keys from the root hash and from all nested hashes and arrays. + # The values are unchanged. + def deep_transform_keys!(&block) + @parameters.deep_transform_keys!(&block) + self + end + # Deletes a key-value pair from +Parameters+ and returns the value. If # +key+ is not found, returns +nil+ (or, with optional code block, yields # +key+ and returns the result). Cf. +#extract!+, which returns the diff --git a/actionpack/test/controller/parameters/accessors_test.rb b/actionpack/test/controller/parameters/accessors_test.rb index 7b9b716a42..cb49eeb1b7 100644 --- a/actionpack/test/controller/parameters/accessors_test.rb +++ b/actionpack/test/controller/parameters/accessors_test.rb @@ -213,6 +213,15 @@ class ParametersAccessorsTest < ActiveSupport::TestCase assert_kind_of ActionController::Parameters, @params.transform_keys!.each { |k| k } end + test "deep_transform_keys retains permitted status" do + @params.permit! + assert_predicate @params.deep_transform_keys { |k| k }, :permitted? + end + + test "deep_transform_keys retains unpermitted status" do + assert_not_predicate @params.deep_transform_keys { |k| k }, :permitted? + end + test "transform_values retains permitted status" do @params.permit! assert_predicate @params.transform_values { |v| v }, :permitted? diff --git a/actionpack/test/controller/parameters/mutators_test.rb b/actionpack/test/controller/parameters/mutators_test.rb index 312b1e5b27..31ee7964f5 100644 --- a/actionpack/test/controller/parameters/mutators_test.rb +++ b/actionpack/test/controller/parameters/mutators_test.rb @@ -118,4 +118,13 @@ class ParametersMutatorsTest < ActiveSupport::TestCase test "transform_values! retains unpermitted status" do assert_not_predicate @params.transform_values! { |v| v }, :permitted? end + + test "deep_transform_keys! retains permitted status" do + @params.permit! + assert_predicate @params.deep_transform_keys! { |k| k }, :permitted? + end + + test "deep_transform_keys! retains unpermitted status" do + assert_not_predicate @params.deep_transform_keys! { |k| k }, :permitted? + end end diff --git a/activerecord/lib/active_record/associations/collection_proxy.rb b/activerecord/lib/active_record/associations/collection_proxy.rb index 85e0f076da..797d647900 100644 --- a/activerecord/lib/active_record/associations/collection_proxy.rb +++ b/activerecord/lib/active_record/associations/collection_proxy.rb @@ -1029,7 +1029,7 @@ module ActiveRecord alias_method :append, :<< alias_method :concat, :<< - def prepend(*args) + def prepend(*args) # :nodoc: raise NoMethodError, "prepend on association is not defined. Please use <<, push or append" end diff --git a/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb b/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb index c32475c683..3756f74c95 100644 --- a/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb +++ b/activerecord/test/cases/adapters/mysql2/case_sensitivity_test.rb @@ -22,7 +22,7 @@ class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase CollationTest.validates_uniqueness_of(:string_ci_column, case_sensitive: false) CollationTest.create!(string_ci_column: "A") invalid = CollationTest.new(string_ci_column: "a") - queries = assert_sql { invalid.save } + queries = capture_sql { invalid.save } ci_uniqueness_query = queries.detect { |q| q.match(/string_ci_column/) } assert_no_match(/lower/i, ci_uniqueness_query) end @@ -31,7 +31,7 @@ class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase CollationTest.validates_uniqueness_of(:string_cs_column, case_sensitive: false) CollationTest.create!(string_cs_column: "A") invalid = CollationTest.new(string_cs_column: "a") - queries = assert_sql { invalid.save } + queries = capture_sql { invalid.save } cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/) } assert_match(/lower/i, cs_uniqueness_query) end @@ -40,7 +40,7 @@ class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase CollationTest.validates_uniqueness_of(:string_ci_column, case_sensitive: true) CollationTest.create!(string_ci_column: "A") invalid = CollationTest.new(string_ci_column: "A") - queries = assert_sql { invalid.save } + queries = capture_sql { invalid.save } ci_uniqueness_query = queries.detect { |q| q.match(/string_ci_column/) } assert_match(/binary/i, ci_uniqueness_query) end @@ -49,7 +49,7 @@ class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase CollationTest.validates_uniqueness_of(:string_cs_column, case_sensitive: true) CollationTest.create!(string_cs_column: "A") invalid = CollationTest.new(string_cs_column: "A") - queries = assert_sql { invalid.save } + queries = capture_sql { invalid.save } cs_uniqueness_query = queries.detect { |q| q.match(/string_cs_column/) } assert_no_match(/binary/i, cs_uniqueness_query) end @@ -58,7 +58,7 @@ class Mysql2CaseSensitivityTest < ActiveRecord::Mysql2TestCase CollationTest.validates_uniqueness_of(:binary_column, case_sensitive: true) CollationTest.create!(binary_column: "A") invalid = CollationTest.new(binary_column: "A") - queries = assert_sql { invalid.save } + queries = capture_sql { invalid.save } bin_uniqueness_query = queries.detect { |q| q.match(/binary_column/) } assert_no_match(/\bBINARY\b/, bin_uniqueness_query) end diff --git a/activerecord/test/cases/calculations_test.rb b/activerecord/test/cases/calculations_test.rb index 33475e2e09..0d13174e12 100644 --- a/activerecord/test/cases/calculations_test.rb +++ b/activerecord/test/cases/calculations_test.rb @@ -185,7 +185,7 @@ class CalculationsTest < ActiveRecord::TestCase def test_limit_is_kept return if current_adapter?(:OracleAdapter) - queries = assert_sql { Account.limit(1).count } + queries = capture_sql { Account.limit(1).count } assert_equal 1, queries.length assert_match(/LIMIT/, queries.first) end @@ -193,7 +193,7 @@ class CalculationsTest < ActiveRecord::TestCase def test_offset_is_kept return if current_adapter?(:OracleAdapter) - queries = assert_sql { Account.offset(1).count } + queries = capture_sql { Account.offset(1).count } assert_equal 1, queries.length assert_match(/OFFSET/, queries.first) end @@ -201,14 +201,14 @@ class CalculationsTest < ActiveRecord::TestCase def test_limit_with_offset_is_kept return if current_adapter?(:OracleAdapter) - queries = assert_sql { Account.limit(1).offset(1).count } + queries = capture_sql { Account.limit(1).offset(1).count } assert_equal 1, queries.length assert_match(/LIMIT/, queries.first) assert_match(/OFFSET/, queries.first) end def test_no_limit_no_offset - queries = assert_sql { Account.count } + queries = capture_sql { Account.count } assert_equal 1, queries.length assert_no_match(/LIMIT/, queries.first) assert_no_match(/OFFSET/, queries.first) @@ -224,15 +224,12 @@ class CalculationsTest < ActiveRecord::TestCase end def test_apply_distinct_in_count - queries = assert_sql do + queries = capture_sql do Account.distinct.count Account.group(:firm_id).distinct.count end queries.each do |query| - # `table_alias_length` in `column_alias_for` would execute - # "SHOW max_identifier_length" statement in PostgreSQL adapter. - next if query == "SHOW max_identifier_length" assert_match %r{\ASELECT(?! DISTINCT) COUNT\(DISTINCT\b}, query end end @@ -464,7 +461,7 @@ class CalculationsTest < ActiveRecord::TestCase def test_should_not_perform_joined_include_by_default assert_equal Account.count, Account.includes(:firm).count - queries = assert_sql { Account.includes(:firm).count } + queries = capture_sql { Account.includes(:firm).count } assert_no_match(/join/i, queries.last) end diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index 2417775ef1..4ec695c4c6 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -706,7 +706,7 @@ class RelationTest < ActiveRecord::TestCase end def test_to_sql_on_eager_join - expected = assert_sql { + expected = capture_sql { Post.eager_load(:last_comment).order("comments.id DESC").to_a }.first actual = Post.eager_load(:last_comment).order("comments.id DESC").to_sql diff --git a/guides/source/engines.md b/guides/source/engines.md index 3031c62928..90b08b00f0 100644 --- a/guides/source/engines.md +++ b/guides/source/engines.md @@ -1511,34 +1511,35 @@ These are the hooks you can use in your own code. To hook into the initialization process of one of the following classes use the available hook. -| Class | Available Hooks | -| --------------------------------- | ------------------------------------ | -| `ActionCable` | `action_cable` | -| `ActionCable::Channel::Base` | `action_cable_channel` | -| `ActionCable::Connection::Base` | `action_cable_connection` | -| `ActionController::API` | `action_controller_api` | -| `ActionController::API` | `action_controller` | -| `ActionController::Base` | `action_controller_base` | -| `ActionController::Base` | `action_controller` | -| `ActionController::TestCase` | `action_controller_test_case` | -| `ActionDispatch::IntegrationTest` | `action_dispatch_integration_test` | -| `ActionDispatch::SystemTestCase` | `action_dispatch_system_test_case` | -| `ActionMailbox::Base` | `action_mailbox` | -| `ActionMailbox::InboundEmail` | `action_mailbox_inbound_email` | -| `ActionMailbox::TestCase` | `action_mailbox_test_case` | -| `ActionMailer::Base` | `action_mailer` | -| `ActionMailer::TestCase` | `action_mailer_test_case` | -| `ActionText::Content` | `action_text_content` | -| `ActionText::RichText` | `action_text_rich_text` | -| `ActionView::Base` | `action_view` | -| `ActionView::TestCase` | `action_view_test_case` | -| `ActiveJob::Base` | `active_job` | -| `ActiveJob::TestCase` | `active_job_test_case` | -| `ActiveRecord::Base` | `active_record` | -| `ActiveStorage::Attachment` | `active_storage_attachment` | -| `ActiveStorage::Blob` | `active_storage_blob` | -| `ActiveSupport::TestCase` | `active_support_test_case` | -| `i18n` | `i18n` | +| Class | Available Hooks | +| -------------------------------------| ------------------------------------ | +| `ActionCable` | `action_cable` | +| `ActionCable::Channel::Base` | `action_cable_channel` | +| `ActionCable::Connection::Base` | `action_cable_connection` | +| `ActionCable::Connection::TestCase` | `action_cable_connection_test_case` | +| `ActionController::API` | `action_controller_api` | +| `ActionController::API` | `action_controller` | +| `ActionController::Base` | `action_controller_base` | +| `ActionController::Base` | `action_controller` | +| `ActionController::TestCase` | `action_controller_test_case` | +| `ActionDispatch::IntegrationTest` | `action_dispatch_integration_test` | +| `ActionDispatch::SystemTestCase` | `action_dispatch_system_test_case` | +| `ActionMailbox::Base` | `action_mailbox` | +| `ActionMailbox::InboundEmail` | `action_mailbox_inbound_email` | +| `ActionMailbox::TestCase` | `action_mailbox_test_case` | +| `ActionMailer::Base` | `action_mailer` | +| `ActionMailer::TestCase` | `action_mailer_test_case` | +| `ActionText::Content` | `action_text_content` | +| `ActionText::RichText` | `action_text_rich_text` | +| `ActionView::Base` | `action_view` | +| `ActionView::TestCase` | `action_view_test_case` | +| `ActiveJob::Base` | `active_job` | +| `ActiveJob::TestCase` | `active_job_test_case` | +| `ActiveRecord::Base` | `active_record` | +| `ActiveStorage::Attachment` | `active_storage_attachment` | +| `ActiveStorage::Blob` | `active_storage_blob` | +| `ActiveSupport::TestCase` | `active_support_test_case` | +| `i18n` | `i18n` | ## Configuration hooks |